Можно ли удалить из нескольких таблиц в одной инструкции SQL?

можно удалить с помощью операторов join, чтобы квалифицировать набор для удаления, например:

DELETE J
FROM Users U
inner join LinkingTable J on U.id = J.U_id
inner join Groups G on J.G_id = G.id

WHERE G.Name = 'Whatever'
and U.Name not in ('Exclude list')

однако я заинтересован в удалении обеих сторон критериев соединения - обоих LinkingTable запись и запись пользователя, от которых он зависит. Я не могу включить каскады, потому что мое решение-это код Entity Framework, а двунаправленные отношения-для нескольких каскадных путей.

В идеале, я хотел бы что-то например:

DELETE J, U
FROM Users U
inner join LinkingTable J on U.id = J.U_id
...

синтаксически это не работает, но мне интересно, возможно ли что-то подобное?

5 ответов


нет, вам нужно будет запустить несколько операторов.

поскольку вам нужно удалить из двух таблиц, подумайте о создании временной таблицы соответствующих идентификаторов:

SELECT U.Id INTO #RecordsToDelete
FROM Users U
   JOIN LinkingTable J ON U.Id = J.U_Id
...

а затем удалить из каждой таблицы:

DELETE FROM Users 
WHERE Id IN (SELECT Id FROM #RecordsToDelete)

DELETE FROM LinkingTable
WHERE Id IN (SELECT Id FROM #RecordsToDelete)

как вы говорите, возможно в MY SQL но не на SQL SERVER

вы можете использовать "удаленную" псевдо-таблицу для удаления значений из двух таблиц одновременно, например,

 begin transaction;

 declare @deletedIds table ( samcol1 varchar(25) );

 delete #temp1
 output deleted.samcol1 into @deletedIds
 from #temp1 t1
 join #temp2 t2
 on t2.samcol1 = t1.samcol1

 delete #temp2
 from #temp2 t2
 join @deletedIds d
 on d.samcol1 = t2.samcol1;

 commit transaction;

для краткого объяснения вы можете взглянуть на это ссылке

и знать использование удаленной таблицы вы можете следовать этому С использованием inserted и deleted


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

этот подход может иметь огромное влияние на вашу сторону приложения, если у вас нет некоторых флагов для visualization государство или status

что-то вроде

  1. INSERT фиктивные не видимые строки для пользователей (с чем-то вроде Id = -1 для фиктивных значений)
  2. добавить LinkingTable альтернативный столбец точка к Users, Я называю это U_ComesFrom

    ALTER TABLE LinkingTagble добавить U_ComesFrom_U_id INT по умолчанию (-1)

  3. добавить FOREIGN KEY С NOCHECK

    изменить таблицу LinkingTable с NOCHECK
    Внешний ключ (U_ComesFrom_U_id)
    Ссылки пользователей (Id);

  4. добавить Users колонки

    пользователи ALTER TABLE добавляют бит MarkedForDeletion не NULL По умолчанию (0)

тогда ваш SQL будет выглядеть как

BEGIN TRANSACTION
    UPDATE J
    SET U_Comes_From_U_id = U_ID, U_id = -1 -- or some N/R value that you define in Users
    FROM Users U
    inner join LinkingTable J on U.id = J.U_id
    inner join Groups G on J.G_id = G.id
    WHERE G.Name = 'Whatever'
    and U.Name not in ('Exclude list')

    UPDATE U
    SET MarkedForDeletion = 1
    FROM Users
    inner join LinkingTable J on U.id = J.U_ComesFrom_U_id 
    WHERE U_id > 0

    DELETE FROM LinkingTable 
    WHERE U_ComesFrom_U_id > 0

    DELETE FROM Users
    WHERE MarkedForDeletion = 1

COMMIT

этот подход повлияет на производительность, так как каждая транзакция будет составлять не менее 4 операций DML на двунаправленные ключи.


используйте TRY CATCH с транзакцией

BEGIN TRANSACTION
BEGIN TRY
    DELETE from A WHERE id=1

    DELETE FROM b WHERE id=1

    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
END CATCH

или для этого также можно использовать процедуру Store Использование Хранимой Процедуры С Транзакцией:


Если вы создаете внешний ключ через T-SQL, вы должны добавить параметр on DELETE CASCADE к внешнему ключу:

Code Snippet 

ALTER TABLE <tablename>
ADD CONSTRAINT <constraintname> FOREIGN KEY (<columnname(s)>)
REFERENCES <referencedtablename> (<columnname(s)>)

ON DELETE CASCADE;