Is it possible to delete from multiple tables in the same SQL statement?
It's possible to delete using join statements to qualify the set to be deleted, such as the following:
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')
However I'm interested in deleting both sides of the join criteria -- both the LinkingTable
record and the User record on which it depends. I can't turn cascades on because my solution is Entity Framework code first and the bidirectional relationships make for multiple cascade paths.
Ideally, I'd like something like:
DELETE J, U
FROM Users U
inner join LinkingTable J on U.id = J.U_id
...
Syntactically this doesn't work out, but I'm curious if something like this is possible?
Nope, you'd need to run multiple statements.
Because you need to delete from two tables, consider creating a temp table of the matching ids:
SELECT U.Id INTO #RecordsToDelete
FROM Users U
JOIN LinkingTable J ON U.Id = J.U_Id
...
And then delete from each of the tables:
DELETE FROM Users
WHERE Id IN (SELECT Id FROM #RecordsToDelete)
DELETE FROM LinkingTable
WHERE Id IN (SELECT Id FROM #RecordsToDelete)
The way you say is Possible in MY SQL
but not for SQL SERVER
You can use of the "deleted" pseudo table for deleting the values from Two Tables at a time like,
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;
For brief Explanation you can take a look at this Link
and to Know the Use of Deleted Table you can follow this Using the inserted and deleted Tables
The only way I could think of is logically break the bi-directional foreign keys in a procedural way.
This approach can have huge impact to your application side if you don't have some flags for visualization
state or status
Something like
-
INSERT
dummy not visible rows to Users (with something likeId = -1
for dummy values) -
Add to
LinkingTable
an alternative column to point back toUsers
, I'll call itU_ComesFrom
ALTER TABLE LinkingTagble ADD U_ComesFrom_U_id INT DEFAULT(-1)
-
Add
FOREIGN KEY
with aNOCHECK
ALTER TABLE LinkingTable WITH NOCHECK
FOREIGN KEY (U_ComesFrom_U_id)
REFERENCES Users (Id) ; -
Add to
Users
columnALTER TABLE Users ADD MarkedForDeletion BIT NOT NULL DEFAULT(0)
Then your SQL would look like
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
This approach would impact the performance since each transaction would be at least 4 DML operations per bi-directional keys.
Use TRY CATCH with Transaction
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
or you can also use Store procedure for same Using Stored Procedure With Transaction:
If you are creating the foreign key through T-SQL you must append the ON DELETE CASCADE option to the foreign key:
Code Snippet
ALTER TABLE <tablename>
ADD CONSTRAINT <constraintname> FOREIGN KEY (<columnname(s)>)
REFERENCES <referencedtablename> (<columnname(s)>)
ON DELETE CASCADE;