web-dev-qa-db-fra.com

Est-il possible de supprimer de plusieurs tables dans la même instruction SQL?

Il est possible de supprimer à l'aide d'instructions de jointure pour qualifier l'ensemble à supprimer, par exemple:

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')

Toutefois, je suis intéressé par la suppression des deux côtés des critères de jointure - 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 permettent de créer plusieurs chemins en cascade.

Idéalement, j'aimerais quelque chose comme:

DELETE J, U
FROM Users U
inner join LinkingTable J on U.id = J.U_id
...

Syntaxiquement, cela ne marche pas, mais je suis curieux de savoir si une telle chose est possible.

28
bwerks

Non, vous devez exécuter plusieurs déclarations. 

Puisque vous devez supprimer de deux tables, envisagez de créer une table temporaire avec les identifiants correspondants:

SELECT U.Id INTO #RecordsToDelete
FROM Users U
   JOIN LinkingTable J ON U.Id = J.U_Id
...

Et puis supprimez de chacune des tables:

DELETE FROM Users 
WHERE Id IN (SELECT Id FROM #RecordsToDelete)

DELETE FROM LinkingTable
WHERE Id IN (SELECT Id FROM #RecordsToDelete)
34
sgeddes

La façon dont vous dites est possible dans MY SQL mais pas pour SQL SERVER

Vous pouvez utiliser la pseudo-table "supprimé" pour supprimer les valeurs de deux tables à la fois, par exemple:

 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 à ceci Link

et connaître l'utilisation de la table supprimée, vous pouvez suivre ceci Utiliser les tables insérées et supprimées

3
Rajesh

Le seul moyen auquel je puisse penser est de casser logiquement les clés étrangères bidirectionnelles d'une manière procédurale

Cette approche peut avoir un impact considérable sur votre application si vous ne disposez pas d'indicateurs pour visualization state ou status.

Quelque chose comme 

  1. INSERT lignes factices non visibles pour les utilisateurs (avec quelque chose comme Id = -1 pour les valeurs factices)
  2. Ajoutez à LinkingTable une colonne alternative pour renvoyer à Users, je l'appellerai U_ComesFrom 

    ALTER TABLE LinkingTagble ADD U_ComesFrom_U_id INT DEFAULT (-1)

  3. Ajouter FOREIGN KEY avec une NOCHECK

    ALTER TABLE LinkingTable AVEC NOCHECK
    FOREIGN KEY (U_ComesFrom_U_id)
    RÉFÉRENCES Utilisateurs (Id);

  4. Ajouter à la colonne Users

    ALTER TABLE Utilisateurs AJOUTER MarkedForDeletion BIT NOT NULL DEFAULT (0)

Ensuite, 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 les performances puisque chaque transaction représenterait au moins 4 opérations DML par clé bidirectionnelle.

2
Luis LL

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 Store pour celle-ci Utilisation de la procédure stockée avec transaction:

1
uma

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;
1
Nagu