T-SQL: Birleştirmeler yoluyla silinecek satırları seçme


494

Senaryo:

Diyelim ki iki tablom var, TableA ve TableB. TableB'nin birincil anahtarı tek bir sütundur (BId) ve TableA'da yabancı bir anahtar sütundur.

Benim durumumda, TableB TableB belirli satırlarla bağlantılı tüm satırları kaldırmak istiyorum: Bunu birleştirme yoluyla yapabilir miyim? Birleştirilen tüm satırlar birleştirilsin mi?

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

Yoksa bunu yapmak zorunda mıyım:

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

Sormamın nedeni, bana göre ilk seçeneğin daha büyük masalarla uğraşırken çok daha verimli olacağı.

Teşekkürler!

Yanıtlar:


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

çalışmalı


1
Bir Where cümlesi yerine birleşimde And [filtre koşulumu] kullandım. Her ikisinin de işe yarayacağını düşünürdüm, ancak birleştirme üzerindeki filtre koşulu, birleşimden elde ettiğiniz sonuçları sınırlandıracaktır.
TheTXI

10
Bir soru. Neden 'SİL' yerine 'SİLME TableA FROM' yazmamız gerekiyor? Sadece bu durumda işe yaradığını görüyorum, ama neden?
LaBracca

66
Sanırım kayıtları silmek için hangi tabloyu belirtmeniz gerekiyor. Ben sadece sözdizimi ile bir sorgu koştu DELETE TableA, TableB ...ve bu aslında her iki ilgili kayıtları sildi. Güzel.
Andrew

1
PostgreSQL'de join ile sözdizimi çalışmaz, ancak "using" anahtar sözcüğünü kullanmak mümkündür. DELETE from TableA a using TableB b where b.Bid = a.Bid and [my filter condition]
bartolo-otrit

8
MySQL hata "MULTI DELETE içinde bilinmeyen tablo 'TableA' alırsınız ve bunun nedeni TableA (a) için bir takma ad bildirmiş olmanızdır. Küçük ayar:DELETE a FROM TableA a INNER JOIN TableB b on b.Bid = a.Bid and [my filter condition]
masam

260

Bu sözdizimini kullanırdım

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

7
Ben de bu sözdizimini tercih ediyorum, olan biteni mantıklı bir şekilde biraz daha mantıklı görünüyor. Ayrıca, bir UPDATE için aynı tür sözdizimini kullanabileceğinizi biliyorum.
Adam Nofsinger

Bunu da tercih ederim, çünkü silme işleminden sonra tablo diğer adının yerleştirilmesi, neyin silinmekte olduğu konusunda her zaman daha sezgisel görünüyordu.
Jagd

14
Aslında bu benim için de tercih ediliyor. Özellikle aynı masaya katılmam gereken durumlarda (örneğin, yinelenen kayıtları silmek için). Bu durumda, sildiğim "yan" için bir takma ad kullanmanız gerekiyor ve bu sözdizimi, yinelenen takma addan sildiğim süper netleştiriyor.
Chris Simmons

29

Evet yapabilirsin. Misal :

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

8
İlk satırdaki tabloya diğer adıyla başvurmayı tercih ederim. Bu, "TableA'yı Sil" yerine "Sil" şeklindedir. Tablonun kendisiyle birleşmesi durumunda, hangi tarafı silmek istediğinizi netleştirir.
Jeremy Stein

10

Bir erişim veritabanı ile bunu yapmaya çalışıyordu ve ben silindikten hemen sonra bir. * Kullanmak için gerekli bulundu .

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

Reddedilmeyi bekleyen düzenlemeden: "UniqueRecords özelliğinin evet olarak ayarlanması gerekir, aksi takdirde çalışmaz. ( Support.microsoft.com/kb/240098 )"
StuperUser

8

Neredeyse aynı olduğunu MySQL , ancak kullanmak zorunda tablo diğer adı kelime "SİL" sonra hakkını:

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

2

Yukarıdaki sözdizimi Interbase 2007'de çalışmaz. Bunun yerine şöyle bir şey kullanmak zorunda kaldım:

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

(Not Interbase, takma adlar için AS anahtar sözcüğünü desteklemez)


2

Bunu kullanıyorum

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

@ @TXI yolu yeterince iyi ama cevapları ve yorumları okudum ve bir şeyin cevaplanması gerektiğini buldum, WHERE yan tümcesinde veya birleştirme koşulu olarak koşul kullanıyor. Bu yüzden test etmeye ve bir pasaj yazmaya karar verdim ancak aralarında anlamlı bir fark bulamadım. Burada sql betiğini görebiliyorsunuz ve önemli nokta, bu kesin cevap olmadığı için comnet olarak yazmayı tercih ettim, ancak büyük ve yorumlara konulamıyor, lütfen affedin.

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

Bu senaryodan iyi bir neden alabilir veya başka bir faydalı yazı yazabiliyorsanız lütfen paylaşın. Teşekkürler ve umarım bu yardım.


1

Diyelim ki biri Master seti (örn. Çalışanlar) ve diğeri alt seti (ör. Bağımlılar) olan 2 tablonuz var ve Bağımlılar tablosundaki anahtarlama yapamayan tüm veri satırlarından kurtulmak istiyorsunuz Ana tablodaki tüm satırlarla.

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)

Burada dikkat edilmesi gereken nokta, birleştirme işleminden önce EmpID'lerin bir 'dizisini' topluyor olmanızdır; Bağımlılıklar tablosunda bir Silme işlemi yapmak için bu EmpID'leri kullanarak.


1

SQLite'de çalışan tek şey beauXjames'in cevabına benzer bir şeydir.

Bu aşağı geliyor gibi görünüyor DELETE FROM table1 WHERE table1.col1 IN (SOME TEMPORARY TABLE); ve bazı geçici tablo SELECT tarafından sandıklanabilir ve bu geçici tablo Tablo1 kayıtlarını silmek istediğiniz koşula göre filtreleyebilirsiniz iki tablo KATILABİLİR.


1

bu sorguyu çalıştırabilirsiniz: -

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


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

Birleştirmeler ile DML sorgularının kullanımını en aza indirin. Yukarıdaki gibi alt sorgularla tüm DML sorgularının çoğunu yapabilmeniz gerekir.

Genel olarak, birleştirmeler yalnızca 2 veya daha fazla tabloda sütunlara göre SEÇME veya GRUPLAMA yapmanız gerektiğinde kullanılmalıdır. Bir popülasyon tanımlamak için yalnızca birden çok tabloya dokunuyorsanız, alt sorgular kullanın. DELETE sorguları için ilişkili alt sorgu kullanın.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.