133

In MySQL you can use the syntax

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

How do I do the same thing in SQL Server?

OMG Ponies
  • 325,700
  • 82
  • 523
  • 502
Byron Whitlock
  • 52,691
  • 28
  • 123
  • 168

13 Answers13

134

You can take advantage of the "deleted" pseudo table in this example. Something like:

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;

Obviously you can do an 'output deleted.' on the second delete as well, if you needed something to join on for the third table.

As a side note, you can also do inserted.* on an insert statement, and both inserted.* and deleted.* on an update statement.

EDIT: Also, have you considered adding a trigger on table1 to delete from table2 + 3? You'll be inside of an implicit transaction, and will also have the "inserted." and "deleted." pseudo-tables available.

The Conspiracy
  • 3,495
  • 1
  • 17
  • 18
John Gibb
  • 10,603
  • 2
  • 37
  • 48
  • 2
    Is it better to just DELETE FROM table1 WHERE id = x and then delete from next table instead of using inner join and going through all of this extra text?? Basically, skipping the inner join I just need 2 simple queries.... Or is this method any more efficient? – Colandus Mar 10 '13 at 13:16
  • I think it depends on how complicated your where clause is. For a complicated one, this would be better because it only happens once. But for a simpler where clause that affects a lot of rows, your proposal would probably be more efficient since it doesn't have to hold many ids in a table variable. – John Gibb Sep 18 '13 at 15:30
  • @JohnGibb, How does this answer work? Can you explain this answer so that a MySQL dev can understand it? – Pacerier Apr 09 '15 at 14:33
  • @Pacerier I'm not very familiar with MySQL. The idea is that the first delete is only deleting from table1, but it's saving the IDs that were deleted into a variable. The subsequent two statements how uses that variable to delete the associated rows from table2 and table 3. – John Gibb Apr 09 '15 at 17:09
  • @JohnGibb, Now *that's* clear. You should include that in the answer. – Pacerier Apr 11 '15 at 16:59
16

You can use JOIN syntax in FROM clause in DELETE in SQL Server but you still delete from first table only and it's proprietary Transact-SQL extension which is alternative to sub-query.

From example here:

 -- 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
  • 19,091
  • 9
  • 63
  • 102
  • 3
    Example D: 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; – Mark A Dec 13 '12 at 18:19
15
  1. You can always set up cascading deletes on the relationships of the tables.

  2. You can encapsulate the multiple deletes in one stored procedure.

  3. You can use a transaction to ensure one unit of work.

Aaron Daniels
  • 9,563
  • 6
  • 45
  • 58
  • 3
    Definitely possible to delete on a join statement, I just have want to delete from more than one table at a time. – Byron Whitlock Apr 24 '09 at 16:58
  • Wrong answer, joins can be used with delete – rboarman Nov 04 '10 at 18:06
  • ad 1.) That is not true, it might not always be possible. There are some scenarios where you cannot set up cascading deletes, e.g. cycles or multiple cascade paths. (see https://stackoverflow.com/a/3548225/108374 for example) – Tom Pažourek May 30 '18 at 13:14
13

Example for delete some records from master table and corresponding records from two detail tables:

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
Pavel Hodek
  • 14,319
  • 3
  • 32
  • 37
  • 2
    Could you use `SELECT INTO #DeleteIds` instead of `CREATE TABLE 'DeleteIds` followed by `INSERT INTO 'DeleteIds...`? – Caltor Sep 26 '17 at 12:24
9

Basically, no you have to make three delete statements in a transaction, children first and then parents. Setting up cascading deletes is a good idea if this is not a one-off thing and its existence won't conflict with any existing trigger setup.

Yishai
  • 90,445
  • 31
  • 189
  • 263
  • I was hoping I didn't have to do that, I suppose I'll have to select the ID's into a temp table since the relationship isn't a parent child one. once the rows from one table is gone there is no way to get the other rows. – Byron Whitlock Apr 24 '09 at 17:01
9

Just wondering.. is that really possible in MySQL? it will delete t1 and t2? or I just misunderstood the question.

But if you just want to delete table1 with multiple join conditions, just don't alias the table you want to delete

this:

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

should be written like this to work in MSSQL:

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

to contrast how the other two common RDBMS do a delete operation:

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

Michael Buen
  • 38,643
  • 9
  • 94
  • 118
4

In SQL server there is no way to delete records from multiple tables using join. So you have to delete from child first before delete form parent.

Jonno
  • 436
  • 1
  • 4
  • 13
tiny
  • 173
  • 1
  • 9
  • Something like this: DELETE ChildTable Where id=@id (new line) DELETE ParentTable Where id=@id? (ids are PK and FK) – paraJdox1 Feb 05 '21 at 08:03
2

All has been pointed out. Just use either DELETE ON CASCADE on the parent table or delete from the child-table and then parent.

paraJdox1
  • 805
  • 9
  • 23
kayode
  • 21
  • 1
  • What do you mean by delete from child table to the parent? do you mean by using joins technique like the one showed in question or aforementioned answers? – Imran Faruqi Apr 19 '20 at 23:38
2

This is an alternative way of deleting records without leaving orphans.


Declare @user Table(keyValue int  , someString varchar(10))
insert into @user
values(1,'1 value')

insert into @user
values(2,'2 value')

insert into @user
values(3,'3 value')

Declare @password Table(  keyValue int , details varchar(10))
insert into @password
values(1,'1 Password')
insert into @password
values(2,'2 Password')
insert into @password
values(3,'3 Password')

        --before deletion
  select * from @password a inner join @user b
                on a.keyvalue = b.keyvalue
  select * into #deletedID from @user where keyvalue=1 -- this works like the output example
  delete  @user where keyvalue =1
  delete @password where keyvalue in (select keyvalue from #deletedid)

  --After deletion--
  select * from @password a inner join @user b
                on a.keyvalue = b.keyvalue

hidden
  • 3,216
  • 8
  • 47
  • 69
1

As Aaron has already pointed out, you can set delete behaviour to CASCADE and that will delete children records when a parent record is deleted. Unless you want some sort of other magic to happen (in which case points 2, 3 of Aaron's reply would be useful), I don't see why would you need to delete with inner joins.

Peter Perháč
  • 20,434
  • 21
  • 120
  • 152
0

To build upon John Gibb's answer, for deleting a set of data in two tables with a FK relationship:

--*** 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
  • 5,799
  • 4
  • 34
  • 30
-4
DELETE     TABLE1 LIN
FROM TABLE1 LIN
INNER JOIN TABLE2 LCS ON  CONDITION
WHERE CONDITION
McDowell
  • 107,573
  • 31
  • 204
  • 267
ARUN
  • 7
-5

$sql="DELETE FROM basic_tbl,education_tbl, personal_tbl ,address_tbl,department_tbl USING 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);