T-SQL: selezione di righe da eliminare tramite join


494

Scenario:

Diciamo che ho due tabelle, TableA e TableB. La chiave primaria di TableB è una singola colonna (BId) ed è una colonna di chiave esterna in TableA.

Nella mia situazione, desidero rimuovere tutte le righe in TableA che sono collegate a righe specifiche in TableB: posso farlo attraverso i join? Eliminare tutte le righe che vengono estratte dai join?

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

O sono costretto a fare questo:

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

Il motivo per cui lo chiedo è che la prima opzione sarebbe molto più efficace quando si trattano tavoli più grandi.

Grazie!

Risposte:


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

dovrebbe funzionare


1
Ho usato E [la mia condizione di filtro] sul join anziché una clausola Where. Immagino che entrambi funzionerebbero, ma la condizione del filtro sul join limiterà i risultati del join.
TheXI

10
Una domanda. Perché dobbiamo scrivere "ELIMINA Tabella DA DA" anziché "ELIMINA DA"? Vedo che funziona solo in questo caso, ma perché?
LaBracca,

66
Penso perché devi indicare da quale tabella eliminare i record. Ho appena eseguito una query con la sintassi DELETE TableA, TableB ...e che ha effettivamente eliminato i record pertinenti da entrambi. Bello.
Andrew,

1
In PostgreSQL la sintassi con join non funziona ma è possibile usare la parola chiave "using". DELETE from TableA a using TableB b where b.Bid = a.Bid and [my filter condition]
bartolo-otrit,

8
In MySQL viene visualizzato l'errore "Tabella sconosciuta 'TableA' in MULTI DELETE" e questo perché hai dichiarato un alias per TableA (a). Piccola regolazione:DELETE a FROM TableA a INNER JOIN TableB b on b.Bid = a.Bid and [my filter condition]
masam

260

Vorrei usare questa sintassi

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

7
Preferisco anche questa sintassi, sembra logicamente un po 'più logico cosa sta succedendo. Inoltre, so che puoi utilizzare questo stesso tipo di sintassi per un AGGIORNAMENTO.
Adam Nofsinger,

Lo preferisco anche io, perché il posizionamento dell'alias della tabella dopo DELETE mi è sempre sembrato più intuitivo su ciò che viene eliminato.
Jagd,

14
Anzi, questo è preferito anche per me. Soprattutto nei casi in cui ho bisogno di unirmi sulla stessa tabella (ad es. Per cancellare record duplicati). In tal caso, devo usare un alias per il "lato" da cui sto eliminando e questa sintassi rende super chiaro che sto eliminando dall'alias duplicato.
Chris Simmons,

29

Si, puoi. Esempio :

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

8
Preferisco fare riferimento alla tabella nella prima riga dal suo alias. Questo è "Elimina un" anziché "Elimina tabella A". Nel caso in cui ti unisci al tavolo con se stesso, chiarisce da che parte vuoi eliminare.
Jeremy Stein,

10

Stavo provando a farlo con un database di accesso e ho scoperto che dovevo usare un. * Subito dopo l'eliminazione.

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

Dalla modifica in sospeso respinto: "La proprietà UniqueRecords deve essere impostata su Sì, altrimenti non funzionerà (. Support.microsoft.com/kb/240098 )"
StuperUser

8

È quasi lo stesso in MySQL , ma devi usare l' alias della tabella subito dopo la parola "ELIMINA":

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

2

La sintassi sopra non funziona in Interbase 2007. Invece, ho dovuto usare qualcosa come:

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

(Nota Interbase non supporta la parola chiave AS per gli alias)


2

Sto usando questo

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

e il modo @TheTXI è abbastanza buono, ma ho letto le risposte e i commenti e ho trovato una cosa a cui bisogna rispondere è usare la condizione nella clausola WHERE o come condizione di join. Così ho deciso di provarlo e scrivere uno snippet ma non ho trovato differenze significative tra loro. Puoi vedere lo script sql qui e il punto importante è che ho preferito scriverlo come commnet perché questa non è una risposta esatta ma è grande e non può essere inserita nei commenti, ti prego di scusarmi.

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

Se puoi ottenere buone ragioni da questo script o scrivere un altro utile, ti preghiamo di condividere. Grazie e spero che questo aiuto.


1

Supponiamo che tu abbia 2 tabelle, una con un set Master (ad es. Employees) e una con un set figlio (ad es. Dipendenti) e vuoi sbarazzarti di tutte le righe di dati nella tabella Dipendenti che non riescono a digitare con qualsiasi riga nella tabella 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)

Il punto da notare qui è che stai solo raccogliendo prima un 'array' di EmpID dal join, usando quell'insieme di EmpID per eseguire un'operazione di cancellazione nella tabella Dipendenti.


1

In SQLite, l'unica cosa che funziona è qualcosa di simile alla risposta di beauXjames.

Sembra arrivare a questo DELETE FROM table1 WHERE table1.col1 IN (SOME TEMPORARY TABLE); e che alcune tabelle temporanee possono essere create da SELECT e JOIN per le tue due tabelle, che puoi filtrare questa tabella temporanea in base alla condizione in cui desideri eliminare i record in Table1.


1

puoi eseguire questa query: -

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

1

Il modo più semplice è:

DELETE TableA
FROM TableB
WHERE TableA.ID = TableB.ID

1
DELETE FROM table1
where id IN 
    (SELECT id FROM table2..INNER JOIN..INNER JOIN WHERE etc)

Riduci al minimo l'uso di query DML con Joins. Dovresti essere in grado di eseguire la maggior parte delle query DML con sottoquery come sopra.

In generale, i join devono essere utilizzati solo quando è necessario SELEZIONARE o Raggruppare per colonne in 2 o più tabelle. Se si toccano solo più tabelle per definire una popolazione, utilizzare le sottoquery. Per le query DELETE, utilizzare una query secondaria correlata.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.