T-SQL: Вибір рядків для видалення за допомогою приєднання


494

Сценарій:

Скажімо, у мене дві таблиці, TableA і TableB. Первинний ключ TableB - це один стовпець (BId) і є стовпцем із зовнішнім ключем у TableA.

У своїй ситуації я хочу видалити всі рядки в TableA, які пов'язані з певними рядками в TableB: Чи можу я це зробити через приєднання? Видалити всі рядки, які витягнуті з з'єднань?

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

Або я змушений це зробити:

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

Причину, про яку я запитую, мені здається, що перший варіант був би набагато ефективнішим при роботі з більшими таблицями.

Дякую!

Відповіді:


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

повинні працювати


1
Я використовував And [мій стан фільтра] під час з'єднання замість пункту Where. Я думаю, що обидва будуть працювати, але умова фільтра при з’єднанні обмежить ваші результати приєднання.
TheTXI

10
Одне питання. Чому нам потрібно писати "ВИДАЛИТИ Таблиця ВІД" замість "ВІДКЛЮЧАТИ ВІД"? Я бачу, це працює лише в цьому випадку, але чому?
LaBracca

66
Я думаю, тому що ви повинні вказати, з якої таблиці видалити записи. Я просто запустив запит із синтаксисом, DELETE TableA, TableB ...який фактично видалив відповідні записи з обох. Приємно.
Андрій

1
У синтаксисі PostgreSQL з приєднанням не працює, але можна використовувати ключове слово "використовувати". DELETE from TableA a using TableB b where b.Bid = a.Bid and [my filter condition]
bartolo-otrit

8
У MySQL ви отримаєте помилку "Невідома таблиця" TableA "в MULTI DELETE", і це тому, що ви оголосили псевдонім для TableA (a). Невелике пристосування:DELETE a FROM TableA a INNER JOIN TableB b on b.Bid = a.Bid and [my filter condition]
масам

260

Я використовував би цей синтаксис

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

7
Я також віддаю перевагу цьому синтаксису, схоже, логічно має трохи більше сенсу, що відбувається. Також я знаю, що ви можете використовувати цей самий тип синтаксису для ОНОВЛЕННЯ.
Адам Нофсінгер

Я також вважаю за краще, тому що розміщення псевдоніму таблиці після DELETE мені завжди здавалося більш інтуїтивним щодо того, що видаляється.
Джагд

14
Дійсно, мені це теж подобається. Зокрема, у випадках, коли мені потрібно фактично приєднатися до однієї таблиці (наприклад, для видалення дублікатів записів). У такому випадку мені потрібно використовувати псевдонім для "сторони", яку я видаляю, і цей синтаксис дає зрозуміти, що я видаляю псевдонім дублікатів.
Кріс Сіммонс

29

Так, ти можеш. Приклад:

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

8
Я вважаю за краще посилатися на таблицю в першому рядку за її псевдонімом. Це "Видалити", а не "Видалити таблицю". У випадку, коли ви приєднаєте таблицю до себе, це дає зрозуміти, яку сторону ви хочете видалити.
Джеремі Штейн

10

Намагався зробити це за допомогою бази даних доступу і виявив, що мені потрібно використовувати . * Відразу після видалення.

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

Від відкинутого відкладеного редагування: «Властивість UniqueRecords повинен бути встановлений так, в іншому випадку він не буде працювати (. Support.microsoft.com/kb/240098
StuperUser

8

Це майже те саме в MySQL , але ви повинні використовувати псевдонім таблиці відразу після слова "DELETE":

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

2

Синтаксис вище не працює в Interbase 2007. Натомість мені довелося використовувати щось на кшталт:

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

(Примітка. Interbase не підтримує ключове слово AS для псевдонімів)


2

Я цим користуюся

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

і спосіб @TheTXI досить хороший, але я читаю відповіді та коментарі, і я виявив, що потрібно відповісти, використовуючи умову в пункті WHERE або як умову приєднання. Тому я вирішив перевірити його і написати фрагмент, але не знайшов значущої різниці між ними. Тут ви можете бачити скрипт sql. Важливим моментом є те, що я вважав за краще писати його як comnet, тому що це не точна відповідь, але він великий і не може ставитись у коментарях, пробачте мене.

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

Якщо ви можете отримати вагомі причини з цього сценарію або написати інше корисне, будь ласка, поділіться. Дякую та сподіваємось, що ця допомога.


1

Скажімо, у вас є дві таблиці: одна з основним набором (наприклад, службовці) та одна з набором даних (наприклад, залежні), і ви хочете позбутися всіх рядків даних у таблиці залежних, які не вдається запустити з будь-якими рядками в таблиці 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)

Слід зазначити, що ви просто збираєте "масив" EmpID з об'єднання спочатку, використовуючи цей набір EmpID, щоб зробити операцію видалення в таблиці Dependents.


1

У SQLite єдине, що працює - це щось подібне до відповіді beauXjames.

Здається, це зводиться до того, DELETE FROM table1 WHERE table1.col1 IN (SOME TEMPORARY TABLE); що деяка тимчасова таблиця може бути створена SELECT і ПРИЄДНАЙТЕ свою дві таблиці, за допомогою яких ви можете фільтрувати цю тимчасову таблицю виходячи з умови, що ви хочете видалити записи в таблиці1.


1

Ви можете запустити цей запит: -

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)

Мінімізуйте використання запитів DML за допомогою Joins. Ви повинні мати можливість виконувати більшість усіх запитів DML з підзапросами, як вище.

Загалом, приєднання повинні використовуватися лише тоді, коли вам потрібно ВИБІРАТИ або ГРУПУвати стовпчики в 2 або більше таблицях. Якщо ви лише торкаєтесь декількох таблиць для визначення сукупності, використовуйте підзапити. Для DELETE-запитів використовуйте співвіднесений підзапит.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.