SQL
Elimina in cascata
Ricerca…
ON DELETE CASCADE
Supponi di avere un'applicazione che amministri le stanze.
Supponiamo inoltre che la tua applicazione funzioni su base client (inquilino).
Hai diversi clienti.
Quindi il tuo database conterrà una tabella per i clienti e una per le stanze.
Ora, ogni cliente ha N stanze.
Questo dovrebbe significare che hai una chiave esterna nella tabella della stanza, facendo riferimento alla tabella del cliente.
ALTER TABLE dbo.T_Room WITH CHECK ADD CONSTRAINT FK_T_Room_T_Client FOREIGN KEY(RM_CLI_ID)
REFERENCES dbo.T_Client (CLI_ID)
GO
Supponendo che un cliente passi ad altri software, dovrai cancellare i suoi dati nel tuo software. Ma se lo fai
DELETE FROM T_Client WHERE CLI_ID = x
Quindi riceverai una violazione di chiave esterna, perché non puoi eliminare il client quando ha ancora stanze.
Ora avresti il codice di scrittura nella tua applicazione che cancella le stanze del cliente prima che cancelli il client. Supponiamo inoltre che in futuro verranno aggiunte molte più dipendenze da chiavi esterne nel tuo database, poiché la funzionalità dell'applicazione si espande. Orribile. Per ogni modifica nel tuo database, dovrai adattare il codice dell'applicazione in N posti. Probabilmente dovrai adattare il codice anche ad altre applicazioni (ad es. Interfacce con altri sistemi).
C'è una soluzione migliore rispetto a farlo nel tuo codice.
Puoi semplicemente aggiungere ON DELETE CASCADE
alla tua chiave esterna.
ALTER TABLE dbo.T_Room -- WITH CHECK -- SQL-Server can specify WITH CHECK/WITH NOCHECK
ADD CONSTRAINT FK_T_Room_T_Client FOREIGN KEY(RM_CLI_ID)
REFERENCES dbo.T_Client (CLI_ID)
ON DELETE CASCADE
Ora puoi dire
DELETE FROM T_Client WHERE CLI_ID = x
e le stanze vengono cancellate automaticamente quando il client viene cancellato.
Problema risolto - senza modifiche al codice dell'applicazione.
Una parola di cautela: in Microsoft SQL-Server, questo non funzionerà se si dispone di una tabella che fa riferimento a se stessa. Quindi, se provi a definire una cascata di eliminazione su una struttura ad albero ricorsiva, in questo modo:
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_T_FMS_Navigation_T_FMS_Navigation]') AND parent_object_id = OBJECT_ID(N'[dbo].[T_FMS_Navigation]'))
ALTER TABLE [dbo].[T_FMS_Navigation] WITH CHECK ADD CONSTRAINT [FK_T_FMS_Navigation_T_FMS_Navigation] FOREIGN KEY([NA_NA_UID])
REFERENCES [dbo].[T_FMS_Navigation] ([NA_UID])
ON DELETE CASCADE
GO
IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_T_FMS_Navigation_T_FMS_Navigation]') AND parent_object_id = OBJECT_ID(N'[dbo].[T_FMS_Navigation]'))
ALTER TABLE [dbo].[T_FMS_Navigation] CHECK CONSTRAINT [FK_T_FMS_Navigation_T_FMS_Navigation]
GO
non funzionerà, perché Microsoft-SQL-server non ti permette di impostare una chiave esterna con ON DELETE CASCADE
su una struttura ad albero ricorsiva. Una ragione per questo è che l'albero è possibilmente ciclico e che potrebbe portare a una situazione di stallo.
D'altra parte, PostgreSQL può farlo;
il requisito è che l'albero non sia ciclico.
Se l'albero è ciclico, otterrai un errore di runtime.
In tal caso, dovrai solo implementare la funzione di cancellazione.
Una parola di cautela:
Questo significa che non puoi semplicemente cancellare e reinserire la tabella del client, perché se lo fai, cancellerà tutte le voci in "T_Room" ... (nessun aggiornamento non delta più)