web-dev-qa-db-fra.com

Comment puis-je supprimer de plusieurs tables en utilisant INNER JOIN dans SQL Server

Dans MySQL, vous pouvez utiliser la syntaxe

DELETE t1,t2 
FROM table1 AS t1 
INNER JOIN table2 t2 ...
INNER JOIN table3 t3 ...

Comment puis-je faire la même chose dans SQL Server?

95
Byron Whitlock

Vous pouvez tirer parti de la pseudo-table "supprimé" dans cet exemple. Quelque chose comme:

begin transaction;

   declare @deletedIds table ( id int );

   delete t1
   output deleted.id into @deletedIds
   from table1 t1
    join table2 t2
      on t2.id = t1.id
    join table3 t3
      on t3.id = t2.id;

   delete t2
   from table2 t2
    join @deletedIds d
      on d.id = t2.id;

   delete t3
   from table3 t3 ...

commit transaction;

Évidemment, vous pouvez faire une "sortie supprimée". sur la deuxième suppression également, si vous aviez besoin de quelque chose à joindre pour la troisième table.

En guise de remarque, vous pouvez également insérer. * Dans une instruction d’insertion, et insérer les deux. * Et supprimé. * Dans une instruction de mise à jour.

EDIT: En outre, avez-vous envisagé d’ajouter un déclencheur à la table 1 pour supprimer de la table 2 + 3? Vous serez à l'intérieur d'une transaction implicite et aurez également les pseudo-tables "insertion ." et "supprimé.".

104
John Gibb
  1. Vous pouvez toujours configurer des suppressions en cascade sur les relations des tables.

  2. Vous pouvez encapsuler les suppressions multiples dans une procédure stockée.

  3. Vous pouvez utiliser une transaction pour assurer une unité de travail.

15
Aaron Daniels

Vous pouvez utiliser la syntaxe JOIN dans la clause FROM dans DELETE dans SQL Server, mais vous ne supprimez toujours que de la première table et son extension propriétaire Transact-SQL, alternative à la sous-requête. 

Par exemple ici :

 -- Transact-SQL extension
 DELETE 
   FROM Sales.SalesPersonQuotaHistory 
     FROM Sales.SalesPersonQuotaHistory AS spqh INNER JOIN 
          Sales.SalesPerson AS sp ON spqh.BusinessEntityID = sp.BusinessEntityID
    WHERE sp.SalesYTD > 2500000.00;
14
topchef

Exemple de suppression de certains enregistrements de la table principale et des enregistrements correspondants de deux tables détaillées:

BEGIN TRAN

  -- create temporary table for deleted IDs
  CREATE TABLE #DeleteIds (
    Id INT NOT NULL PRIMARY KEY
  )

  -- save IDs of master table records (you want to delete) to temporary table    
  INSERT INTO #DeleteIds(Id)
  SELECT DISTINCT mt.MasterTableId
  FROM MasterTable mt 
  INNER JOIN ... 
  WHERE ...  

  -- delete from first detail table using join syntax
  DELETE d
  FROM DetailTable_1 D
  INNER JOIN #DeleteIds X
    ON D.MasterTableId = X.Id


  -- delete from second detail table using IN clause  
  DELETE FROM DetailTable_2
  WHERE MasterTableId IN (
    SELECT X.Id
    FROM #DeleteIds X
  )


  -- and finally delete from master table
  DELETE d
  FROM MasterTable D
  INNER JOIN #DeleteIds X
    ON D.MasterTableId = X.Id

  -- do not forget to drop the temp table
  DROP TABLE #DeleteIds

COMMIT
11
Pavel Hodek

Je me demandais simplement… est-ce vraiment possible avec MySQL? il va supprimer t1 et t2? ou j'ai simplement mal compris la question.

Mais si vous souhaitez simplement supprimer table1 avec plusieurs conditions de jointure, n'aliasez pas la table à supprimer.

ce:

DELETE t1,t2 
FROM table1 AS t1 
INNER JOIN table2 t2 ...
INNER JOIN table3 t3 ...

devrait être écrit comme ceci pour fonctionner dans MSSQL:

DELETE table1
FROM table1 
INNER JOIN table2 t2 ...
INNER JOIN table3 t3 ...

pour mettre en contraste la manière dont les deux autres SGBDR communs effectuent une opération de suppression:

http://mssql-to-postgresql.blogspot.com/2007/12/deleting-duplicates-in-postgresql-ms.html

9
Michael Buen

En gros, non, vous devez faire trois déclarations de suppression dans une transaction, les enfants d'abord, puis les parents. La configuration des suppressions en cascade est une bonne idée s'il ne s'agit pas d'une opération ponctuelle et que son existence ne sera pas en conflit avec une configuration de déclencheur existante.

7
Yishai

Dans SQL Server, il n’existe aucun moyen de supprimer plusieurs tables à l’aide de join . Vous devez donc supprimer d’abord de l’enfant avant de supprimer le formulaire parent.

3
tiny

C’est une autre façon de supprimer des enregistrements sans laisser d’orphelins.


 Déclare la table @user (keyValue int, someString varchar (10)) 
 Insérer dans @user 
 Valeurs (1, '1 valeur') 

 Insérer dans @user
 valeurs (2, '2 valeur') 

 insérer dans @utilisateur 
 valeurs (3, 'valeur 3) 

 Déclare @password Table (keyValue int, details varchar ( 10)) 
 Insérer dans @password 
 Valeurs (1, '1 mot de passe') 
 Insérer dans @ motdepasse 
 Valeurs (2, '2 mot de passe') 
 Insérer dans @ motpasse 
values ​​(3, '3 Password') 

 --avant suppression 
 sélectionnez * depuis @password une jointure interne @user b 
 sur a.keyvalue = b.keyvalue 
 sélectionnez * dans #deletedID à partir de @user où keyvalue = 1 - cela fonctionne comme dans l'exemple de sortie 
 delete @user où keyvalue = 1 
 delete @password où keyvalue in (sélectionnez keyvalue dans #deletedid) 

 --Après suppression --
 sélectionnez * depuis @password une jointure interne @user b 
 sur a.keyvalue = b.keyvalue 

2
hidden

Tout a été signalé. Il suffit d'utiliser soit DELETE ON CASCADE sur le parent table ou de supprimer du child-table au parent.

2
kayode

Comme Aaron l'a déjà souligné, vous pouvez définir le comportement de suppression sur CASCADE, ce qui supprimera les enregistrements enfants lorsqu'un enregistrement parent est supprimé. À moins que vous souhaitiez une autre sorte de magie (auquel cas les points 2, 3 de la réponse d'Aaron seraient utiles), je ne vois pas pourquoi vous auriez besoin de supprimer avec des jointures internes.

1
Peter Perháč

Pour compléter la réponse de John Gibb, supprimez un ensemble de données dans deux tables avec une relation FK:

--*** To delete from tblMain which JOINs to (has a FK of) tblReferredTo's PK  
--       i.e.  ON tblMain.Refer_FK = tblReferredTo.ID
--*** !!! If you're CERTAIN that no other rows anywhere also refer to the 
--      specific rows in tblReferredTo !!!
BEGIN TRAN;

    --*** Keep the ID's from tblReferredTo when we DELETE from tblMain
    DECLARE @tblDeletedRefs TABLE ( ID INT );
    --*** DELETE from the referring table first
    DELETE FROM tblMain 
    OUTPUT DELETED.Refer_FK INTO @tblDeletedRefs  -- doesn't matter that this isn't DISTINCT, the following DELETE still works.
    WHERE ..... -- be careful if filtering, what if other rows 
                --   in tblMain (or elsewhere) also point to the tblReferredTo rows?

    --*** Now we can remove the referred to rows, even though tblMain no longer refers to them.
    DELETE tblReferredTo
    FROM   tblReferredTo INNER JOIN @tblDeletedRefs Removed  
            ON tblReferredTo.ID = Removed.ID;

COMMIT TRAN;
0
AjV Jsy