T-SQL: Memilih baris yang akan dihapus melalui gabungan


494

Skenario:

Katakanlah saya punya dua tabel, TableA dan TableB. Kunci utama TableB adalah kolom tunggal (BId), dan merupakan kolom kunci asing di TableA.

Dalam situasi saya, saya ingin menghapus semua baris di TableA yang terkait dengan baris tertentu di TableB: Dapatkah saya melakukannya melalui gabungan? Hapus semua baris yang ditarik dari gabungan?

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

Atau apakah saya terpaksa melakukan ini:

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

Alasan saya bertanya adalah bagi saya sepertinya opsi pertama akan jauh lebih efisien ketika berhadapan dengan tabel yang lebih besar.

Terima kasih!

Jawaban:


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

harus bekerja


1
Saya menggunakan Dan [kondisi filter saya] pada gabungan alih-alih klausa Di mana. Saya membayangkan keduanya akan berfungsi, tetapi kondisi filter pada join akan membatasi hasil Anda dari join.
TheTXI

10
Satu pertanyaan. Mengapa kita perlu menulis 'DELETE TableA FROM', bukan 'DELETE FROM'? Saya melihat ini hanya berfungsi dalam kasus ini, tetapi mengapa?
LaBracca

66
Saya pikir karena Anda harus menunjukkan tabel mana untuk menghapus catatan. Saya baru saja menjalankan kueri dengan sintaks DELETE TableA, TableB ...dan itu benar-benar menghapus catatan yang relevan dari keduanya. Bagus.
Andrew

1
Dalam sintaksis PostgreSQL dengan join tidak berfungsi tetapi dimungkinkan untuk menggunakan kata kunci "using". DELETE from TableA a using TableB b where b.Bid = a.Bid and [my filter condition]
bartolo-otrit

8
Di MySQL Anda akan mendapatkan kesalahan "Tabel tidak dikenal 'TableA' di MULTI DELETE" dan itu karena Anda mendeklarasikan alias untuk TableA (a). Penyesuaian kecil:DELETE a FROM TableA a INNER JOIN TableB b on b.Bid = a.Bid and [my filter condition]
masam

260

Saya akan menggunakan sintaks ini

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

7
Saya lebih suka sintaks ini juga, tampaknya membuat sedikit lebih masuk akal secara logis apa yang terjadi. Juga, saya tahu Anda dapat menggunakan jenis sintaksis yang sama untuk PEMBARUAN.
Adam Nofsinger

Saya lebih suka juga, karena penempatan tabel alias setelah DELETE selalu tampak lebih intuitif bagi saya tentang apa yang sedang dihapus.
Jagd

14
Memang, ini lebih disukai untuk saya juga. Khususnya dalam kasus di mana saya harus benar-benar bergabung di meja yang sama (misalnya untuk menghapus rekaman duplikat). Dalam hal ini, saya perlu menggunakan alias untuk "sisi" yang saya hapus dan sintaks ini membuatnya sangat jelas saya menghapus dari alias duplikat.
Chris Simmons

29

Ya kamu bisa. Contoh:

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

8
Saya lebih suka merujuk ke tabel di baris pertama dengan aliasnya. Itu adalah "Hapus a" daripada "Hapus TableA". Dalam kasus di mana Anda bergabung dengan tabel itu sendiri, itu membuat jelas sisi mana yang ingin Anda hapus.
Jeremy Stein

10

Sedang mencoba melakukan ini dengan akses database dan menemukan saya perlu menggunakan . * Tepat setelah penghapusan.

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

Dari ditolak tertunda edit: "Properti UniqueRecords harus set ke yes, jika tidak maka tidak akan bekerja (. Support.microsoft.com/kb/240098 )"
StuperUser

8

Hampir sama di MySQL , tetapi Anda harus menggunakan tabel alias tepat setelah kata "DELETE":

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

2

Sintaks di atas tidak berfungsi di Interbase 2007. Sebagai gantinya, saya harus menggunakan sesuatu seperti:

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

(Catatan Interbase tidak mendukung kata kunci AS untuk alias)


2

Saya menggunakan ini

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

dan cara @TheTXI cukup baik tetapi saya membaca jawaban dan komentar dan saya menemukan satu hal yang harus dijawab adalah menggunakan kondisi dalam klausa WHERE atau sebagai kondisi bergabung. Jadi saya memutuskan untuk mengujinya dan menulis cuplikan tetapi tidak menemukan perbedaan yang berarti di antara mereka. Anda dapat melihat skrip sql di sini dan poin pentingnya adalah bahwa saya lebih suka menuliskannya sebagai commnet karena ini bukan jawaban yang pasti tetapi besar dan tidak dapat dimasukkan ke dalam komentar, maafkan saya.

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

Jika Anda bisa mendapatkan alasan yang bagus dari skrip ini atau menulis yang bermanfaat lainnya, silakan bagikan. Terima kasih dan harap bantuan ini.


1

Katakanlah Anda memiliki 2 tabel, satu dengan set Master (mis. Karyawan) dan satu dengan set anak (mis. Tanggungan) dan Anda ingin menyingkirkan semua baris data dalam tabel Dependen yang tidak dapat memasukkan kunci dengan baris apa pun di tabel Master.

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)

Poin yang perlu diperhatikan di sini adalah Anda hanya mengumpulkan 'larik' EmpID dari join terlebih dahulu, menggunakan set EmpID tersebut untuk melakukan operasi Penghapusan pada tabel Dependents.


1

Dalam SQLite, satu-satunya hal yang berfungsi adalah sesuatu yang mirip dengan jawaban beauXjames.

Tampaknya turun ke ini DELETE FROM table1 WHERE table1.col1 IN (SOME TEMPORARY TABLE); dan bahwa beberapa tabel sementara dapat dibuat oleh SELECT dan GABUNG dua tabel Anda yang Anda bisa memfilter tabel sementara ini berdasarkan kondisi yang Anda ingin menghapus catatan di Table1.


1

Anda dapat menjalankan kueri ini: -

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

1

Cara yang lebih sederhana adalah:

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)

Minimalkan penggunaan kueri DML dengan Bergabung. Anda harus dapat melakukan sebagian besar dari semua kueri DML dengan subkueri seperti di atas.

Secara umum, gabungan hanya boleh digunakan ketika Anda perlu SELECT atau GROUP dengan kolom dalam 2 tabel atau lebih. Jika Anda hanya menyentuh beberapa tabel untuk menentukan populasi, gunakan subqueries. Untuk kueri HAPUS, gunakan subquery berkorelasi.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.