126 votes

Comment supprimer des données de plusieurs tables en utilisant INNER JOIN en 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 ?

129voto

John Gibb Points 4473

Vous pouvez tirer parti du pseudo tableau "supprimé" 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;

Bien entendu, vous pouvez également effectuer une "sortie supprimée" lors de la deuxième suppression, si vous avez besoin de quelque chose à joindre pour la troisième table.

Par ailleurs, vous pouvez également utiliser inserted.* dans une instruction d'insertion, et inserted.* et deleted.* dans une instruction de mise à jour.

EDITAR: En outre, avez-vous envisagé d'ajouter un déclencheur sur la table 1 pour supprimer de la table 2 + 3 ? Vous serez à l'intérieur d'une transaction implicite, et vous aurez également le "inserted. " et " supprimé ". "Des pseudo-tables sont disponibles.

2 votes

Est-il préférable de simplement SUPPRIMER DE TABLE1 WHERE id = x puis de supprimer de la table suivante au lieu d'utiliser la jointure interne et de passer par tout ce texte supplémentaire ? En fait, en sautant la jointure interne, je n'ai besoin que de deux requêtes simples..... Cette méthode est-elle plus efficace ?

0 votes

Je pense que cela dépend de la complexité de votre clause where. Pour une clause compliquée, ce serait mieux car cela ne se produit qu'une fois. Mais pour une clause where plus simple qui affecte un grand nombre de lignes, votre proposition serait probablement plus efficace puisqu'elle n'a pas à contenir de nombreux identifiants dans une variable de table.

0 votes

@JohnGibb, Comment cette réponse fonctionne-t-elle ? Pouvez-vous expliquer cette réponse afin qu'un développeur MySQL puisse la comprendre ?

15voto

Aaron Daniels Points 6052
  1. Vous pouvez toujours mettre en place 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.

3 votes

Il est tout à fait possible d'effectuer une suppression sur une instruction de jointure, mais je veux simplement supprimer des données de plusieurs tables à la fois.

0 votes

Mauvaise réponse, les jointures peuvent être utilisées avec la suppression.

0 votes

Ad 1.) Ce n'est pas vrai, ce n'est pas toujours possible. Il existe certains scénarios dans lesquels vous ne pouvez pas configurer de suppressions en cascade, par exemple des cycles ou des chemins de cascade multiples. (voir stackoverflow.com/a/3548225/108374 par exemple)

15voto

topchef Points 7473

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

De l'exemple aquí :

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

3 votes

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 ;

12voto

Pavel Hodek Points 2488

Exemple pour supprimer certains enregistrements de la table principale et les 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

2 votes

Pourriez-vous utiliser SELECT INTO #DeleteIds au lieu de CREATE TABLE 'DeleteIds suivi par INSERT INTO 'DeleteIds... ?

8voto

Yishai Points 42417

Fondamentalement, non, vous devez faire trois déclarations de suppression dans une transaction, les enfants d'abord, puis les parents. La mise en place de suppressions en cascade est une bonne idée s'il ne s'agit pas d'une opération ponctuelle et si son existence n'entre pas en conflit avec la configuration d'un déclencheur existant.

0 votes

J'espérais ne pas avoir à le faire, je suppose que je vais devoir sélectionner les ID dans une table temporaire puisque la relation n'est pas parent-enfant. Une fois que les lignes d'une table ont disparu, il n'y a aucun moyen d'obtenir les autres lignes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X