Come si usa l'eliminazione a cascata con SQL Server?


332

Ho 2 tabelle: T1 e T2, sono tabelle esistenti con dati. Abbiamo una o più relazioni tra T1 e T2. Come posso modificare le definizioni della tabella per eseguire l'eliminazione a cascata in SQL Server quando viene eliminato un record da T1, anche tutti i record associati in T2.

Il vincolo straniero è in atto tra di loro. Non voglio eliminare le tabelle o creare un trigger per eseguire l'eliminazione per T2. Ad esempio, quando elimino un dipendente, anche tutti i record delle recensioni dovrebbero essere spariti.

T1 - Dipendente,

Employee ID      
Name
Status

T2 - Recensioni delle prestazioni,

Employee ID - 2009 Review
Employee ID - 2010 Review

Risposte:


362

Avrai bisogno di,

  • Elimina il vincolo di chiave esterna esistente,
  • Aggiungine uno nuovo con l' ON DELETE CASCADEimpostazione abilitata.

Qualcosa di simile a:

ALTER TABLE dbo.T2
   DROP CONSTRAINT FK_T1_T2   -- or whatever it's called

ALTER TABLE dbo.T2
   ADD CONSTRAINT FK_T1_T2_Cascade
   FOREIGN KEY (EmployeeID) REFERENCES dbo.T1(EmployeeID) ON DELETE CASCADE

3
Io e la mia squadra abbiamo appena fatto questo. Abbiamo dovuto DROP i nostri vincoli e aggiungerli di nuovo. Questo ha funzionato per noi.
Daniel L. VanDenBosch,

2
In che modo questo è a favore di una cancellazione definitiva? Una cancellazione soft non avrebbe mai avuto un problema di vincolo. Sembra esattamente il contrario di me.
Maxx

2
@Maxx Nell'eliminazione definitiva, elimini un record e non devi preoccuparti dei registri orfani, mentre nell'eliminazione graduale devi farlo manualmente.
Ronaldo Araújo Alves,

319

Per aggiungere "Elimina in cascata" a una chiave esterna esistente in SQL Server Management Studio:

Innanzitutto, seleziona la tua chiave esterna e apri "DROP and Create To .." in una nuova finestra Query.

inserisci qui la descrizione dell'immagine

Quindi, basta aggiungere ON DELETE CASCADEal ADD CONSTRAINTcomando:

n E premi il pulsante "Esegui" per eseguire questa query.

A proposito, per ottenere un elenco delle tue chiavi esterne e vedere quali hanno attivato "Elimina a cascata", puoi eseguire questo script:

SELECT 
   OBJECT_NAME(f.parent_object_id) AS 'Table name',
   COL_NAME(fc.parent_object_id,fc.parent_column_id) AS 'Field name',
   delete_referential_action_desc AS 'On Delete'
FROM sys.foreign_keys AS f,
     sys.foreign_key_columns AS fc,
     sys.tables t 
WHERE f.OBJECT_ID = fc.constraint_object_id
AND t.OBJECT_ID = fc.referenced_object_id
ORDER BY 1

E se ti accorgi che non è possibile DROPuna determinata tabella a causa di un vincolo di chiave esterna, ma non riesci a capire quale FK sta causando il problema, puoi eseguire questo comando:

sp_help 'TableName'

L'SQL in quell'articolo elenca tutti gli FK che fanno riferimento a una tabella particolare.

Spero che tutto ciò aiuti.

Ci scusiamo per il dito lungo. Stavo solo cercando di fare un punto.


163

È possibile farlo con SQL Server Management Studio.

→ Fai clic con il pulsante destro del mouse sul design della tabella e vai su Relazioni e scegli la chiave esterna nel riquadro di sinistra e nel riquadro di destra, espandi il menu "INSERT and UPDATE specific" e seleziona "Cascade" come Elimina regola.

SQL Server Management Studio


ciao, qual è la differenza tra i 4, l'attivazione a cascata rende semplice l'eliminazione di tutti i dati in una tabella. Come posso visualizzare tutte le dipendenze / chiavi fk su questa tabella, non da questa tabella. Anche dopo aver eliminato tutti gli FK ricevo ancora un errore
aggie

@aggie - È possibile controllare le dipendenze facendo clic con il pulsante destro del mouse sulla tabella -> "Visualizza dipendenze" Inoltre il server sql fornisce l'errore dettagliato con il nome della tabella e il nome della colonna come questo "L'istruzione DELETE è in conflitto con il vincolo di RIFERIMENTO" FK_Child1_Parent1 ". Il conflitto si è verificato nel database "TESTDB", tabella "dbo.Child1", colonna "Parent1ID". "
Palanikumar

@aggie - Anche il quarto caso "Imposta predefinito" è, Devi impostare il vincolo predefinito nella colonna Chiave esterna, quando eliminiamo il genitore, il valore predefinito verrà sostituito nelle tabelle figlio. (Nota: il valore predefinito deve corrispondere alla tabella padre.) Per maggiori informazioni visita mssqltips.com/sqlservertip/2365/…
Palanikumar il

Questo è molto utile Mi chiedo, perché non esiste una regola di inserimento? In altre parole, quando aggiungo una riga a T1, voglio che la voce corrispondente in T2 venga creata automaticamente.
Robert M.,

@RobertM. Perché non ha senso. Come farebbe a sapere quali valori INSERIRE? Potresti essere in grado di utilizzare i trigger INSERT per generare le righe secondarie, prova a cercarlo.
Dan Bechard

47

Usa qualcosa di simile

ALTER TABLE T2
ADD CONSTRAINT fk_employee
FOREIGN KEY (employeeID)
REFERENCES T1 (employeeID)
ON DELETE CASCADE;

Inserisci i nomi delle colonne corretti e dovresti essere impostato. Come indicato correttamente da mark_s, se è già presente un vincolo di chiave esterna, potrebbe essere necessario eliminare prima quello vecchio e quindi crearne uno nuovo.


41
@marc_s - in realtà, puoi aggiungere una seconda chiave esterna esattamente contro le stesse colonne su entrambi i lati e funzionerà correttamente. Se si lavora in un ambiente di produzione senza tempi di inattività, potrebbe essere preferibile introdurre il nuovo FK con cascata, quindi rilasciare l'FK precedente, anziché lasciare una finestra sul tavolo quando non è presente alcun FK. (Appena testato su SQL 2008)
Damien_The_Unbeliever il

Questo è corretto. Ho provato questo e funziona. Non è necessario eliminare i primi vincoli di chiave esterna. Grazie per la risposta.
Bichvan Nguyen,

15

Prima di abilitare la proprietà ONCascade:

1. Eliminare il vincolo di chiave esterna esistente

2. aggiungerne uno nuovo con l'impostazione ON DELETE CASCADE abilitata

Ex:

IF EXISTS(SELECT 1 FROM sys.foreign_keys WHERE parent_object_id = OBJECT_ID(N'dbo.Response'))
 BEGIN 

ALTER TABLE [dbo].[Response] DROP CONSTRAINT [FK_Response_Request]  

ALTER TABLE [dbo].[Response] WITH CHECK ADD CONSTRAINT [FK_Response_Request]  FOREIGN KEY([RequestId])
REFERENCES [dbo].[Request] ([RequestId])
ON DELETE CASCADE
END

ELSE

 BEGIN 
 ALTER TABLE [dbo].[Response] WITH CHECK ADD CONSTRAINT [FK_Response_Request]  FOREIGN KEY([RequestId])
REFERENCES [dbo].[Request] ([RequestId])
ON DELETE CASCADE
END

Secondo per disabilitare la proprietà ONCascade:

1. Eliminare il vincolo di chiave esterna esistente

2. Aggiungine uno nuovo con l'impostazione ON DELETE NO ACTION abilitata

Ex:

IF EXISTS(SELECT 1 FROM sys.foreign_keys WHERE parent_object_id = OBJECT_ID(N'dbo.Response'))
 BEGIN 
ALTER TABLE [dbo].[Response] DROP CONSTRAINT [FK_Response_Request]  

ALTER TABLE [dbo].[Response] WITH CHECK ADD CONSTRAINT [FK_Response_Request]  FOREIGN KEY([RequestId])
REFERENCES [dbo].[Request] ([RequestId])
ON DELETE CASCADE
END

ELSE

 BEGIN 
 ALTER TABLE [dbo].[Response] WITH CHECK ADD CONSTRAINT [FK_Response_Request]  FOREIGN KEY([RequestId])
REFERENCES [dbo].[Request] ([RequestId])
ON DELETE NO ACTION 
END

15

ON DELETE CASCADE
Specifica che i dati figlio vengono eliminati quando vengono eliminati i dati padre.

CREATE TABLE products
( product_id INT PRIMARY KEY,
  product_name VARCHAR(50) NOT NULL,
  category VARCHAR(25)
);

CREATE TABLE inventory
( inventory_id INT PRIMARY KEY,
  product_id INT NOT NULL,
  quantity INT,
  min_level INT,
  max_level INT,
  CONSTRAINT fk_inv_product_id
    FOREIGN KEY (product_id)
    REFERENCES products (product_id)
    ON DELETE CASCADE
);

Per questa chiave esterna, abbiamo specificato la ON DELETE CASCADEclausola che dice a SQL Server di eliminare i record corrispondenti nella tabella figlio quando vengono eliminati i dati nella tabella padre. Pertanto, in questo esempio, se un valore product_id viene eliminato dalla tabella dei prodotti, verranno eliminati anche i record corrispondenti nella tabella di inventario che utilizzano questo product_id.


-2

Se la relazione da una a molte va da T1 a T2, allora non rappresenta una funzione e quindi non può essere utilizzata per dedurre o inferire una funzione inversa che garantisce che il valore T2 risultante non ometta le tuple di T1 join T2 che sono deduttivamente valide , perché non esiste una funzione inversa valida deduttivamente. (Rappresentando le funzioni era lo scopo delle chiavi primarie.) La risposta in SQL pensa che sì, è possibile farlo. La risposta nel pensiero relazionale è no, non puoi farlo. Vedi i punti di ambiguità in Codd 1970. Il rapporto dovrebbe essere molti-a-uno dal T1 al T2.


-10

Penso che non si possa semplicemente eliminare la proprietà delle tabelle e, se si tratta di dati di produzione effettivi, è sufficiente eliminare i contenuti che non influiscono sullo schema della tabella.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.