web-dev-qa-db-fra.com

T-SQL: Sélection de lignes à supprimer via des jointures

Scénario:

Disons que j'ai deux tables, TableA et TableB. La clé primaire de TableB est une colonne unique (BId) et est une colonne de clé étrangère dans TableA.

Dans ma situation, je veux supprimer toutes les lignes de TableA qui sont liées à des lignes spécifiques de TableB: Puis-je le faire via des jointures? Supprimer toutes les lignes extraites des jointures?

DELETE FROM TableA 
FROM
   TableA a
   INNER JOIN TableB b
      ON b.BId = a.BId
      AND [my filter condition]

Ou suis-je obligé de faire ceci:

DELETE FROM TableA
WHERE
   BId IN (SELECT BId FROM TableB WHERE [my filter condition])

La raison pour laquelle je pose cette question est qu’il me semble que la première option serait beaucoup plus efficace lorsqu’il s’agit de tables plus grandes.

Merci!

482
John
DELETE TableA
FROM   TableA a
       INNER JOIN TableB b
               ON b.Bid = a.Bid
                  AND [my filter condition] 

devrait marcher

704
TheTXI

J'utiliserais cette syntaxe

Delete a 
from TableA a
Inner Join TableB b
on  a.BId = b.BId
WHERE [filter condition]
257
cmsjr

Oui, vous pouvez. Exemple :

DELETE TableA 
FROM TableA AS a
INNER JOIN TableB AS b
ON a.BId = b.BId
WHERE [filter condition]
29
Diadistis

J'essayais de faire cela avec une base de données d’accès et j’ai trouvé qu’il me fallait utiliser a. * juste après la suppression.

DELETE a.*
FROM TableA AS a
INNER JOIN TableB AS b
ON a.BId = b.BId
WHERE [filter condition]
10
Tony Emrud

C'est presque la même chose dans MySQL, mais vous devez utiliser le alias de table juste après le mot "DELETE":

DELETE a
FROM TableA AS a
INNER JOIN TableB AS b
ON a.BId = b.BId
WHERE [filter condition]
8
Michael Butler

J'utilise ceci

DELETE TableA 
FROM TableA a
INNER JOIN
TableB b on b.Bid = a.Bid
AND [condition]

et @TheTXI way est suffisant, mais je lis les réponses et les commentaires et j’ai trouvé qu’une chose doit être résolue, c’est d’utiliser la condition dans la clause WHERE ou comme condition de jointure. J'ai donc décidé de le tester et d'écrire un extrait mais je n'ai pas trouvé de différence significative entre eux. Vous pouvez voir le script SQL ici et le point important est que j'ai préféré l'écrire en commnet car ce n'est pas une réponse exacte, mais il est volumineux et ne peut pas être mis en commentaire, veuillez me pardonner.

Declare @TableA  Table
(
  aId INT,
  aName VARCHAR(50),
  bId INT
)
Declare @TableB  Table
(
  bId INT,
  bName VARCHAR(50)  
)

Declare @TableC  Table
(
  cId INT,
  cName VARCHAR(50),
  dId INT
)
Declare @TableD  Table
(
  dId INT,
  dName VARCHAR(50)  
)

DECLARE @StartTime DATETIME;
SELECT @startTime = GETDATE();

DECLARE @i INT;

SET @i = 1;

WHILE @i < 1000000
BEGIN
  INSERT INTO @TableB VALUES(@i, 'nameB:' + CONVERT(VARCHAR, @i))
  INSERT INTO @TableA VALUES(@i+5, 'nameA:' + CONVERT(VARCHAR, @i+5), @i)

  SET @i = @i + 1;
END

SELECT @startTime = GETDATE()

DELETE a
--SELECT *
FROM @TableA a
Inner Join @TableB b
ON  a.BId = b.BId
WHERE a.aName LIKE '%5'

SELECT Duration = DATEDIFF(ms,@StartTime,GETDATE())

SET @i = 1;
WHILE @i < 1000000
BEGIN
  INSERT INTO @TableD VALUES(@i, 'nameB:' + CONVERT(VARCHAR, @i))
  INSERT INTO @TableC VALUES(@i+5, 'nameA:' + CONVERT(VARCHAR, @i+5), @i)

  SET @i = @i + 1;
END

SELECT @startTime = GETDATE()

DELETE c
--SELECT *
FROM @TableC c
Inner Join @TableD d
ON  c.DId = d.DId
AND c.cName LIKE '%5'

SELECT Duration    = DATEDIFF(ms,@StartTime,GETDATE())

Si vous pouviez obtenir de bonnes raisons à partir de ce script ou en écrire un autre utile, veuillez le partager. Merci et espérons cette aide.

2
QMaster

La syntaxe ci-dessus ne fonctionne pas dans Interbase 2007. Au lieu de cela, je devais utiliser quelque chose comme:

DELETE FROM TableA a WHERE [filter condition on TableA] 
  AND (a.BId IN (SELECT a.BId FROM TableB b JOIN TableA a 
                 ON a.BId = b.BId 
                 WHERE [filter condition on TableB]))

(Remarque: Interbase ne prend pas en charge le mot clé AS pour les alias)

2
DavidJ

vous pouvez lancer cette requête: -

Delete from TableA 
from 
TableA a, TableB b 
where a.Bid=b.Bid
AND [my filter condition]
1
Aditya

Supposons que vous avez 2 tables, une avec un ensemble principal (par exemple, Employees) et une avec un ensemble enfant (par exemple, des personnes à charge) et que vous souhaitez supprimer toutes les lignes de données de la table des personnes à charge qui ne peuvent pas être saisies. avec toutes les lignes de la table principale.

delete from Dependents where EmpID in (
select d.EmpID from Employees e 
    right join Dependents d on e.EmpID = d.EmpID
    where e.EmpID is null)

Le point à noter ici est que vous collectez simplement un "tableau" d'empID à partir de la jointure en premier, l'utilisation de cet ensemble d'empID pour effectuer une opération de suppression sur la table Dépendants.

1
beauXjames

Dans SQLite, la seule chose qui fonctionne est similaire à la réponse de beauXjames.

Cela semble descendre à cette DELETE FROM table1 WHERE table1.col1 IN (SOME TEMPORARY TABLE); et que certaines tables temporaires peuvent être créées par SELECT et JOIN vos deux tables et que vous pouvez filtrer cette table temporaire en fonction de la condition voulant que vous vouliez supprimer les enregistrements de Table1.

1
Bhoom Suktitipat

Le moyen le plus simple est:

DELETE TableA
FROM TableB
WHERE TableA.ID = TableB.ID
0
Carlos Barini