Можно ли удалить из нескольких таблиц в одном выражении SQL?
Можно удалить с помощью операторов соединения, чтобы квалифицировать удаляемый набор, например:
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
...
Синтаксически это не сработает, но мне любопытно, возможно ли что-то подобное?
Ответы
Ответ 1
Нет, вам нужно запустить несколько операторов.
Поскольку вам нужно удалить из двух таблиц, подумайте о создании временной таблицы соответствующих идентификаторов:
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)
Ответ 2
Как вы говорите, возможно в 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;
Вкратце Объяснение вы можете посмотреть на Ссылка
и знать использование удаленной таблицы, вы можете следовать этому Использование вставленных и удаленных таблиц
Ответ 3
Единственный способ, о котором я мог думать, логически нарушать двунаправленные внешние ключи процедурным способом.
Этот подход может иметь огромное влияние на вашу сторону приложения, если у вас нет флагов для состояния visualization
или status
Что-то вроде
-
INSERT
dummy not visible rows to Users (с чем-то вроде Id = -1
для фиктивных значений)
-
Добавьте к LinkingTable
альтернативный столбец, чтобы вернуться к Users
, я назову его U_ComesFrom
ALTER TABLE LinkingTagble ADD U_ComesFrom_U_id INT DEFAULT (-1)
-
Добавьте FOREIGN KEY
с помощью NOCHECK
ALTER TABLE LinkingTable WITH NOCHECK
ИНОСТРАННЫЙ КЛЮЧ (U_ComesFrom_U_id)
ССЫЛКИ Пользователи (Id);
-
Добавить в столбец Users
ALTER TABLE Пользователи ADD MarkedForDeletion BIT NOT NULL DEFAULT (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 для двунаправленных ключей.
Ответ 4
Используйте 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 для того же
Использование хранимой процедуры с транзакцией:
Ответ 5
Если вы создаете внешний ключ через T-SQL, вы должны добавить параметр ON DELETE CASCADE к внешнему ключу:
Code Snippet
ALTER TABLE <tablename>
ADD CONSTRAINT <constraintname> FOREIGN KEY (<columnname(s)>)
REFERENCES <referencedtablename> (<columnname(s)>)
ON DELETE CASCADE;