Est-il possible de supprimer de plusieurs tables dans la même instruction SQL?
Il est possible de supprimer en utilisant des instructions join pour qualifier l'ensemble à supprimer, comme ce qui suit:
DELETE J
FROM Users U
inner join LinkingTable J on U.id = J.U_id
inner join Groups G on J.G_id = G.id
WHERE G.Name = 'Whatever'
and U.Name not in ('Exclude list')
Cependant, je suis intéressé par la suppression des deux côtés des critères de jointure-à la fois l'enregistrement LinkingTable
et l'enregistrement utilisateur dont il dépend. Je ne peux pas activer les cascades car ma solution est D'abord le code Entity Framework et les relations bidirectionnelles créent plusieurs chemins en cascade.
Idéalement, je voudrais quelque chose comme:
DELETE J, U
FROM Users U
inner join LinkingTable J on U.id = J.U_id
...
Syntaxiquement ce n'est pas le cas travailler, mais je suis curieux si quelque chose comme ça est possible?
5 réponses
Non, vous devez exécuter plusieurs instructions.
Parce que vous devez supprimer de deux tables, envisagez de créer une table temporaire des ID correspondants:
SELECT U.Id INTO #RecordsToDelete
FROM Users U
JOIN LinkingTable J ON U.Id = J.U_Id
...
Puis Supprimer de chacune des tables:
DELETE FROM Users
WHERE Id IN (SELECT Id FROM #RecordsToDelete)
DELETE FROM LinkingTable
WHERE Id IN (SELECT Id FROM #RecordsToDelete)
La façon dont vous dites qu'il est Possible de MY SQL
, mais pas pour SQL SERVER
Vous pouvez utiliser la pseudo-table "deleted" pour supprimer les valeurs de deux Tables à la fois comme,
begin transaction;
declare @deletedIds table ( samcol1 varchar(25) );
delete #temp1
output deleted.samcol1 into @deletedIds
from #temp1 t1
join #temp2 t2
on t2.samcol1 = t1.samcol1
delete #temp2
from #temp2 t2
join @deletedIds d
on d.samcol1 = t2.samcol1;
commit transaction;
Pour une brève explication, vous pouvez jeter un oeil à ce lien
Et pour connaître l'utilisation de la Table supprimée, vous pouvez suivre cette en utilisant les Tables insérées et supprimées
La seule façon dont je pouvais penser est de casser logiquement les clés étrangères bidirectionnelles d'une manière procédurale .
Cette approche peut avoir un impact énorme sur votre application si vous n'avez pas d'indicateurs pour visualization
state ou status
Quelque Chose comme
-
INSERT
dummy pas de lignes visibles pour les Utilisateurs (avec quelque chose commeId = -1
pour des valeurs factices) -
Ajouter à
LinkingTable
une colonne alternative pour pointer versUsers
, Je l'appelleraiU_ComesFrom
Modifier la TABLE LinkingTagble ajouter U_ComesFrom_U_id INT DEFAULT (-1)
-
Ajouter
FOREIGN KEY
avecNOCHECK
Modifier la table LinkingTable avec NOCHECK
Clé étrangère (U_ComesFrom_U_id)
Références utilisateurs (Id); -
Ajouter à
Users
colonneModifier les utilisateurs de la TABLE ajouter MarkedForDeletion BIT NOT NULL DEFAULT (0)
Alors votre SQL ressemblerait à
BEGIN TRANSACTION
UPDATE J
SET U_Comes_From_U_id = U_ID, U_id = -1 -- or some N/R value that you define in Users
FROM Users U
inner join LinkingTable J on U.id = J.U_id
inner join Groups G on J.G_id = G.id
WHERE G.Name = 'Whatever'
and U.Name not in ('Exclude list')
UPDATE U
SET MarkedForDeletion = 1
FROM Users
inner join LinkingTable J on U.id = J.U_ComesFrom_U_id
WHERE U_id > 0
DELETE FROM LinkingTable
WHERE U_ComesFrom_U_id > 0
DELETE FROM Users
WHERE MarkedForDeletion = 1
COMMIT
Cette approche aurait un impact sur la performance puisque chaque transaction serait au moins 4 opérations DML par clés bidirectionnelles.
Utiliser TRY CATCH avec Transaction
BEGIN TRANSACTION
BEGIN TRY
DELETE from A WHERE id=1
DELETE FROM b WHERE id=1
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
END CATCH
Ou vous pouvez également utiliser la procédure de magasin pour même Utilisation De La Procédure Stockée Avec Transaction:
Si vous créez la clé étrangère via T-SQL, vous devez ajouter L'option ON DELETE CASCADE à la clé étrangère:
Code Snippet
ALTER TABLE <tablename>
ADD CONSTRAINT <constraintname> FOREIGN KEY (<columnname(s)>)
REFERENCES <referencedtablename> (<columnname(s)>)
ON DELETE CASCADE;