Як видалити з декількох таблиць за допомогою INNER JOIN на SQL сервері


117

У MySQL ви можете використовувати синтаксис

DELETE t1,t2 
FROM table1 AS t1 
INNER JOIN table2 t2 ...
INNER JOIN table3 t3 ...

Як зробити те ж саме в SQL Server?

Відповіді:


119

Ви можете скористатися "видаленою" псевдо таблицею в цьому прикладі. Щось на зразок:

begin transaction;

   declare @deletedIds table ( id int );

   delete from t1
   output deleted.id into @deletedIds
   from table1 as t1
    inner join table2 as t2
      on t2.id = t1.id
    inner join table3 as t3
      on t3.id = t2.id;

   delete from t2
   from table2 as t2
    inner join @deletedIds as d
      on d.id = t2.id;

   delete from t3
   from table3 as t3 ...

commit transaction;

Очевидно, ви можете зробити «вихід видалений». на другому видаліть також, якщо вам потрібно було щось приєднати до третьої таблиці.

Як бічну примітку, ви також можете вставити. * На оператор вставки та обидва вставлені. * Та видалені. * У операторі оновлення.

EDIT: Ви також розглядали можливість додавання тригера на table1 для видалення з table2 + 3? Ви знаходитесь всередині неявної транзакції, а також будуть доступні псевдо-таблиці «Вставлені. » Та «Видалені ».


2
Чи краще просто ВИДАЛИТИ З таблиці1, де id = x, а потім видалити з наступної таблиці замість використання внутрішнього з'єднання та перегляду всього цього додаткового тексту ?? В основному, пропускаючи внутрішнє з'єднання, мені просто потрібні 2 прості запити .... Або цей метод більш ефективний?
Colandus

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

@JohnGibb, Як працює ця відповідь? Чи можете ви пояснити цю відповідь, щоб розвідник MySQL міг її зрозуміти?
Pacerier

@Pacerier Я не дуже знайомий з MySQL. Ідея полягає в тому, що перше видалення видаляється лише з table1, але це зберігає ідентифікатори, які були видалені у змінну. Наступні два твердження, як використовує цю змінну для видалення пов'язаних рядків з table2 та таблиці 3.
Джон Гібб

@JohnGibb, тепер це зрозуміло. Ви повинні це включити у відповідь.
Pacerier

15
  1. Ви завжди можете встановити каскадні делети на зв'язки таблиць.

  2. Ви можете інкапсулювати кілька видалень за одну збережену процедуру.

  3. Ви можете використовувати транзакцію для забезпечення однієї одиниці роботи.


3
Однозначно можливо видалити з заяви про приєднання, я просто хочу видалити з декількох таблиць одночасно.
Байрон Вітлок

Неправильна відповідь, приєднання може використовуватися для видалення
rboarman

оголошення 1.) Це неправда, це не завжди можливо. Є деякі сценарії, коли ви не можете встановити каскадні делети, наприклад, цикли або кілька каскадних шляхів. (Див stackoverflow.com/a/3548225/108374 , наприклад)
Том Pažourek

15

Ви можете використовувати синтаксис JOIN у пункті FROM в DELETE на SQL Server, але ви все одно видаляєте лише з першої таблиці, і це власне розширення Transact-SQL, яке є альтернативою підзапиту.

З прикладу тут :

 -- Transact-SQL extension
 DELETE 
   FROM Sales.SalesPersonQuotaHistory 
     FROM Sales.SalesPersonQuotaHistory AS spqh INNER JOIN 
          Sales.SalesPerson AS sp ON spqh.BusinessEntityID = sp.BusinessEntityID
    WHERE sp.SalesYTD > 2500000.00;

3
Приклад D: Зняти з продажів.ПродажПерсонQuotaІсторія від продажів.ПродажПерсонQuotaІсторія AS spqh ІНТЕРНЕТ ПРИЄДНАЙТЕСЬ до продажів.ПродажПерсон AS sp ON spqh.BusinessEntityID = sp.BusinessEntityID WHERE sp.SalesYTD> 2500000.00;
Позначте

11

Приклад видалення деяких записів із головної таблиці та відповідних записів із двох таблиць деталей:

BEGIN TRAN

  -- create temporary table for deleted IDs
  CREATE TABLE #DeleteIds (
    Id INT NOT NULL PRIMARY KEY
  )

  -- save IDs of master table records (you want to delete) to temporary table    
  INSERT INTO #DeleteIds(Id)
  SELECT DISTINCT mt.MasterTableId
  FROM MasterTable mt 
  INNER JOIN ... 
  WHERE ...  

  -- delete from first detail table using join syntax
  DELETE d
  FROM DetailTable_1 D
  INNER JOIN #DeleteIds X
    ON D.MasterTableId = X.Id


  -- delete from second detail table using IN clause  
  DELETE FROM DetailTable_2
  WHERE MasterTableId IN (
    SELECT X.Id
    FROM #DeleteIds X
  )


  -- and finally delete from master table
  DELETE d
  FROM MasterTable D
  INNER JOIN #DeleteIds X
    ON D.MasterTableId = X.Id

  -- do not forget to drop the temp table
  DROP TABLE #DeleteIds

COMMIT

1
Чи можете ви використовувати SELECT INTO #DeleteIdsзамість CREATE TABLE 'DeleteIdsних INSERT INTO 'DeleteIds...?
Caltor

9

Цікаво, що це справді можливо в MySQL? це видалить t1 і t2? або я просто неправильно зрозумів питання.

Але якщо ви просто хочете видалити table1 з кількома умовами приєднання, просто не псевдонімуйте таблицю, яку ви хочете видалити

це:

DELETE t1,t2 
FROM table1 AS t1 
INNER JOIN table2 t2 ...
INNER JOIN table3 t3 ...

має бути написано так, щоб це працювало в MSSQL:

DELETE table1
FROM table1 
INNER JOIN table2 t2 ...
INNER JOIN table3 t3 ...

на противагу тому, як інші два поширені RDBMS виконують операцію видалення:

http://mssql-to-postgresql.blogspot.com/2007/12/deleting-duplicates-in-postgresql-ms.html


Дякуємо за підказку SQL Server там, мені довелося налаштувати SQL уздовж цих ліній.
Паук

7

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


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

3

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


2

Це альтернативний спосіб видалення записів, не залишаючи дітей-сиріт.

Оголосити таблицю @user (keyValue int, someString varchar (10))
вставити в @user
значення (1, '1 значення')

вставити в @user
значення (2, '2 значення')

вставити в @user
значення (3, '3 значення')

Оголосити таблицю @password (keyValue int, деталі varchar (10))
вставити в @password
значення (1, '1 пароль')
вставити в @password
значення (2, '2 пароль')
вставити в @password
значення (3, '3 пароль')

        - перед видаленням
  виберіть * з @password внутрішнє з'єднання @user b
                на a.keyvalue = b.keyvalue
  виберіть * у #deletedID від @user, де keyvalue = 1 - це працює, як вихідний приклад
  видаліть @user, де keyvalue = 1
  видаліть @password, де вказано значення ключа (виберіть ключове значення з #deletedid)

  - Після видалення--
  виберіть * з @password внутрішнє з'єднання @user b
                на a.keyvalue = b.keyvalue


2

Все було вказано. Просто використовуйте або DELETE ON CASCADEна батьку tableабо видалити з child-tableдо parent.


Що ви маєте на увазі під видаленням з дочірньої таблиці до батьків? Ви маєте на увазі, використовуючи техніку приєднання, на зразок тієї, яку показали у запитанні, або вищезгаданих відповідей?
Імран Фарукі

1

Як вже вказував Аарон, ви можете встановити поведінку видалення на CASCADE, і це видалить дочірні записи, коли буде видалено батьківський запис. Якщо ви не хочете, щоб відбулася якась інша магія (у цьому випадку пункти 2, 3 відповіді Аарона були б корисні), я не розумію, чому б вам потрібно було видалити з внутрішнім приєднанням.


0

На основі відповіді Джона Гібба для видалення набору даних у двох таблицях із співвідношенням FK:

--*** To delete from tblMain which JOINs to (has a FK of) tblReferredTo's PK  
--       i.e.  ON tblMain.Refer_FK = tblReferredTo.ID
--*** !!! If you're CERTAIN that no other rows anywhere also refer to the 
--      specific rows in tblReferredTo !!!
BEGIN TRAN;

    --*** Keep the ID's from tblReferredTo when we DELETE from tblMain
    DECLARE @tblDeletedRefs TABLE ( ID INT );
    --*** DELETE from the referring table first
    DELETE FROM tblMain 
    OUTPUT DELETED.Refer_FK INTO @tblDeletedRefs  -- doesn't matter that this isn't DISTINCT, the following DELETE still works.
    WHERE ..... -- be careful if filtering, what if other rows 
                --   in tblMain (or elsewhere) also point to the tblReferredTo rows?

    --*** Now we can remove the referred to rows, even though tblMain no longer refers to them.
    DELETE tblReferredTo
    FROM   tblReferredTo INNER JOIN @tblDeletedRefs Removed  
            ON tblReferredTo.ID = Removed.ID;

COMMIT TRAN;

-3
DELETE     TABLE1 LIN
FROM TABLE1 LIN
INNER JOIN TABLE2 LCS ON  CONDITION
WHERE CONDITION

він не буде видалений з двох і більше таблиць. Будь ласка, зрозумійте питання
Камран Шахід

-5

$ sql = "Зняти з basic_tbl ,education_tbl , personal_tbl, address_tbl, department_tbl ВИКОРИСТАННЯ basic_tbl, education_tbl, personal_tbl, address_tbl, department_tbl WHERE b_id= e_id= p_id= a_id= d_id= '" $ ID .. "» «; $ rs = mysqli_query ($ con, $ sql);


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