Comment supprimer de plusieurs tables à l'aide de INNER JOIN dans SQL Server

117

Dans MySQL, vous pouvez utiliser la syntaxe

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

Comment faire la même chose dans SQL Server?

Byron Whitlock
la source

Réponses:

119

Vous pouvez profiter de la pseudo table "supprimée" dans cet exemple. Quelque chose comme:

begin transaction;

   declare @deletedIds table ( id int );

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

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

   delete from t3
   from table3 as t3 ...

commit transaction;

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

En remarque, vous pouvez également faire insert. * Sur une instruction d'insertion, et inséré. * Et supprimé. * Sur une instruction de mise à jour.

EDIT: Avez-vous également envisagé d'ajouter un déclencheur sur la table1 pour supprimer de la table2 + 3? Vous serez à l'intérieur d'une transaction implicite, et vous aurez également les pseudo-tables «inséré » et «supprimé » disponibles.

John Gibb
la source
2
Est-il préférable de simplement SUPPRIMER DE LA table1 WHERE id = x, puis de supprimer de la table suivante au lieu d'utiliser une jointure interne et de parcourir tout ce texte supplémentaire? Fondamentalement, en sautant la jointure interne, j'ai juste besoin de 2 requêtes simples ... Ou cette méthode est-elle plus efficace?
Colandus
Je pense que cela dépend de la complexité de votre clause where. Pour un compliqué, ce serait mieux car cela n'arrive qu'une seule fois. Mais pour une clause where plus simple qui affecte beaucoup de lignes, votre proposition serait probablement plus efficace car elle ne doit pas contenir de nombreux identifiants dans une variable de table.
John Gibb
@JohnGibb, Comment cette réponse fonctionne-t-elle? Pouvez-vous expliquer cette réponse afin qu'un développeur MySQL puisse la comprendre?
Pacerier
@Pacerier Je ne connais pas très bien MySQL. L'idée est que la première suppression ne supprime que de table1, mais enregistre les ID qui ont été supprimés dans une variable. Les deux instructions suivantes comment utilise cette variable pour supprimer les lignes associées du tableau 2 et du tableau 3.
John Gibb
@JohnGibb, maintenant c'est clair. Vous devriez inclure cela dans la réponse.
Pacerier
15
  1. Vous pouvez toujours configurer des suppressions en cascade sur les relations des tables.

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

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

Aaron Daniels
la source
3
Certainement possible de supprimer sur une déclaration de jointure, je veux juste supprimer de plus d'une table à la fois.
Byron Whitlock
Mauvaise réponse, les jointures peuvent être utilisées avec la suppression
rboarman
ad 1.) Ce n'est pas vrai, ce n'est peut-être pas toujours possible. Il existe certains scénarios dans lesquels vous ne pouvez pas configurer des suppressions en cascade, par exemple des cycles ou plusieurs chemins en cascade. (voir stackoverflow.com/a/3548225/108374 par exemple)
Tom Pažourek
15

Vous pouvez utiliser la syntaxe JOIN dans la clause FROM dans DELETE dans SQL Server, mais vous supprimez toujours de la première table uniquement et c'est l'extension Transact-SQL propriétaire qui est une alternative à la sous-requête.

De l'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;
excellent chef
la source
3
Exemple D: 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;
Mark A
11

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
Pavel Hodek
la source
1
Pourriez-vous utiliser SELECT INTO #DeleteIdsau lieu de CREATE TABLE 'DeleteIdssuivi de INSERT INTO 'DeleteIds...?
Caltor le
9

Je me demande juste ... est-ce vraiment possible dans MySQL? il supprimera t1 et t2? ou j'ai juste mal compris la question.

Mais si vous souhaitez simplement supprimer table1 avec plusieurs conditions de jointure, ne créez pas d'alias pour la table que vous souhaitez supprimer

ce:

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

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

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

pour comparer la façon dont les deux autres SGBDR courants effectuent une opération de suppression:

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

Michael Buen
la source
Merci pour l'astuce SQL Server, j'ai dû modifier le SQL dans ce sens.
Pauk
7

Fondamentalement, non, vous devez faire trois instructions de suppression dans une transaction, les enfants d'abord, puis les parents. La configuration de suppressions en cascade est une bonne idée si ce n'est pas une chose ponctuelle et que son existence ne sera pas en conflit avec une configuration de déclencheur existante.

Yishai
la source
J'espérais ne pas avoir à faire cela, je suppose que je devrai sélectionner les identifiants dans une table temporaire car la relation n'est pas une relation parent-enfant. une fois que les lignes d'une table ont disparu, il n'y a aucun moyen d'obtenir les autres lignes.
Byron Whitlock
3

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

minuscule
la source
2

Il s'agit d'une autre façon de supprimer des enregistrements sans laisser d'orphelins.

Declare @user Table (keyValue int, someString varchar (10))
insérer dans @user
valeurs (1, '1 valeur')

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

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

Declare @password Table (keyValue int, details varchar (10))
insérer dans @password
valeurs (1, '1 Mot de passe')
insérer dans @password
valeurs (2, '2 Mot de passe')
insérer dans @password
valeurs (3, '3 Mot de passe')

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

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

caché
la source
2

Tout a été signalé. Utilisez simplement DELETE ON CASCADEsur le parent tableou supprimez du child-tableau parent.

Kayode
la source
Qu'entendez-vous par supprimer de la table enfant au parent? voulez-vous dire en utilisant une technique de jointure comme celle montrée en question ou les réponses susmentionnées?
Imran Faruqi le
1

Comme Aaron l'a déjà souligné, vous pouvez définir le comportement de suppression sur CASCADE et cela supprimera les enregistrements enfants lorsqu'un enregistrement parent est supprimé. À moins que vous ne souhaitiez qu'une sorte d'autre magie se produise (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.

Peter Perháč
la source
0

Pour s'appuyer sur la réponse de John Gibb, pour supprimer 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;
AjV Jsy
la source
-3
DELETE     TABLE1 LIN
FROM TABLE1 LIN
INNER JOIN TABLE2 LCS ON  CONDITION
WHERE CONDITION
ARUN
la source
il ne sera pas supprimé de deux ou plusieurs tables.Veuillez comprendre la question
Kamran Shahid
-5

$ sql = "DELETE FROM basic_tbl, education_tbl, personal_tbl, address_tbl, department_tbl UTILISATION basic_tbl, education_tbl, personal_tbl, address_tbl, department_tbl OU b_id= e_id= p_id= a_id= d_id= '" id $. ». « ; $ rs = mysqli_query ($ con, $ sql);

Dharmesh
la source
Veuillez corriger votre mise en forme et fournir une brève description de la raison pour laquelle votre code fonctionne.
Bryan Herbst