Как удалить из нескольких таблиц с помощью 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;

Очевидно, вы можете сделать «вывод удален». на втором удаляем также, если вам нужно было что-то присоединить к третьей таблице.

В качестве дополнительного примечания вы также можете сделать вставленный. * В операторе вставки и как вставленный. *, Так и удаленный. * В операторе обновления.

РЕДАКТИРОВАТЬ: Кроме того, рассматривали ли вы добавление триггера в table1 для удаления из table2 + 3? Вы будете внутри неявной транзакции, и вам также будут доступны псевдотаблицы «вставлено » и «удалено ».

Джон Гибб
источник
2
Лучше просто УДАЛИТЬ ИЗ table1 WHERE id = x, а затем удалить из следующей таблицы вместо использования внутреннего соединения и просмотра всего этого дополнительного текста? По сути, пропуская внутреннее соединение, мне нужно всего лишь два простых запроса .... Или этот метод более эффективен?
Colandus
Я думаю, это зависит от того, насколько сложен ваш пункт where. Для более сложных это было бы лучше, потому что это происходит только один раз. Но для более простого предложения where, которое влияет на множество строк, ваше предложение, вероятно, будет более эффективным, поскольку оно не должно содержать много идентификаторов в переменной таблицы.
Джон Гибб
@JohnGibb, как работает этот ответ? Можете ли вы объяснить этот ответ, чтобы разработчик MySQL мог его понять?
Pacerier
@Pacerier Я не очень знаком с MySQL. Идея состоит в том, что первое удаление - это только удаление из таблицы 1, но при этом сохраняются удаленные идентификаторы в переменной. Следующие два утверждения, как эта переменная используется для удаления связанных строк из таблицы 2 и таблицы 3.
Джон Гибб,
@JohnGibb, теперь все ясно. Вы должны включить это в ответ.
Pacerier
15
  1. Вы всегда можете настроить каскадное удаление для отношений таблиц.

  2. Вы можете инкапсулировать несколько удалений в одной хранимой процедуре.

  3. Вы можете использовать транзакцию, чтобы гарантировать одну единицу работы.

Аарон Дэниелс
источник
3
Определенно можно удалить в операторе соединения, я просто хочу удалить более чем из одной таблицы за раз.
Байрон Уитлок,
Неверный ответ, объединения можно использовать с удалением
rboarman
ad 1.) Это неправда, это не всегда возможно. Есть несколько сценариев, в которых вы не можете настроить каскадное удаление, например циклы или несколько каскадных путей. (см., например, stackoverflow.com/a/3548225/108374 )
Том Пажурек
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;
topchef
источник
3
Пример D: УДАЛИТЬ ИЗ Sales.SalesPersonQuotaHistory ИЗ Sales.SalesPersonQuotaHistory AS spqh ВНУТРЕННЕЕ СОЕДИНЕНИЕ Sales.SalesPerson AS sp ON spqh.BusinessEntityID = sp.BusinessEntityID ГДЕ sp.SalesYTD> 2500000.00;
Mark A
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 ...

чтобы сравнить, как две другие общие СУБД выполняют операцию удаления:

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

Майкл Буэн
источник
Спасибо за совет по SQL Server, мне пришлось настроить SQL в соответствии с этими строками.
Паук
7

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

Ишай
источник
Я надеялся, что мне не пришлось этого делать, я полагаю, мне придется выбрать идентификаторы во временной таблице, поскольку отношения не являются родительскими и дочерними. после того, как строки из одной таблицы исчезнут, получить другие строки невозможно.
Байрон Уитлок,
3

В SQL-сервере нет возможности удалить несколько таблиц с помощью соединения. Таким образом, вы должны сначала удалить из дочернего элемента, прежде чем удалять родительскую форму.

крошечный
источник
2

Это альтернативный способ удаления записей, не оставляя сирот.

Объявить @user Table (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 a внутреннее соединение @user b
                на a.keyvalue = b.keyvalue
  выберите * в #deletedID из @user, где keyvalue = 1 - это работает как пример вывода
  удалить @user, где keyvalue = 1
  удалить @password, где ключевое значение в (выберите ключевое значение из #deletedid)

  --После удаления--
  выберите * из @password a внутреннее соединение @user b
                на a.keyvalue = b.keyvalue

скрытый
источник
2

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

Kayode
источник
Что вы подразумеваете под удалением из дочерней таблицы по отношению к родительской? Вы имеете в виду, используя технику объединений, подобную той, которая показана в вопросе, или вышеупомянутых ответах?
Имран Фаруки,
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;
AjV Jsy
источник
-3
DELETE     TABLE1 LIN
FROM TABLE1 LIN
INNER JOIN TABLE2 LCS ON  CONDITION
WHERE CONDITION
ARUN
источник
он не будет удален из двух или более таблиц. Пожалуйста, поймите вопрос
Камран Шахид
-5

$ SQL = "DELETE FROM 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 ($ против, $ SQL);

Dharmesh
источник
Исправьте форматирование и кратко опишите, почему ваш код работает.
Bryan Herbst