如何在SQL Server中使用INNER JOIN从多个表中删除

How do I delete from multiple tables using INNER JOIN in SQL server

在MySQL中,您可以使用语法

1
2
3
4
DELETE t1,t2
FROM table1 AS t1
INNER JOIN table2 t2 ...
INNER JOIN table3 t3 ...

如何在SQL Server中执行相同的操作?


您可以利用本例中的"已删除"伪表。比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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;

显然,如果您需要为第三个表加入一些内容,也可以在第二次删除时执行"output deleted."。

作为补充说明,您还可以在insert语句中执行inserted.*操作,在update语句中执行inserted.*和deleted.*操作。

编辑:此外,是否考虑在表1上添加触发器以从表2+3中删除?您将进入一个隐式事务,并且还可以使用"inserted."和"deleted."伪表。


  • 您始终可以在表的关系上设置级联删除。

  • 可以在一个存储过程中封装多个删除。

  • 您可以使用事务来确保一个工作单元。


  • 您可以在SQL Server中的DELETE中的FROM子句中使用联接语法,但仍然只从第一个表中删除,它是专用的Transact-SQL扩展,可以替代子查询。

    从这里的例子来看:

    1
    2
    3
    4
    5
    6
     -- 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;


    例如,从主表中删除一些记录,并从两个明细表中删除相应的记录:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    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


    只是想知道……这在MySQL中真的可行吗?它将删除T1和T2?或者我只是误解了这个问题。

    但是,如果只想删除具有多个联接条件的表1,只需不要对要删除的表进行别名。

    这是:

    1
    2
    3
    4
    DELETE t1,t2
    FROM table1 AS t1
    INNER JOIN table2 t2 ...
    INNER JOIN table3 t3 ...

    应该这样写才能在MSSQL中工作:

    1
    2
    3
    4
    DELETE table1
    FROM table1
    INNER JOIN table2 t2 ...
    INNER JOIN table3 t3 ...

    要对比其他两个常见的RDBMS如何执行删除操作:

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


    基本上,不,您必须在一个事务中生成三条删除语句,先是子语句,然后是父语句。如果这不是一次性的事情,并且它的存在不会与任何现有的触发器设置冲突,那么设置级联删除是一个好主意。


    在SQL Server中,无法使用join删除多个表。因此,在删除窗体父级之前,必须先从子级删除。


    这是删除记录而不留下孤儿的另一种方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    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


    所有的都被指出了。只需在父级table上使用DELETE ON CASCADE或从child-table删除到parent


    正如Aaron已经指出的,您可以将"删除行为"设置为"层叠",这样在删除父记录时将删除子记录。除非您希望发生某种其他魔力(在这种情况下,Aaron回复的第2点、第3点会很有用),否则我不明白为什么需要使用内部联接删除。


    基于John Gibb的回答,删除两个表中具有FK关系的一组数据:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    --*** 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;


    1
    2
    3
    4
    DELETE     TABLE1 LIN
    FROM TABLE1 LIN
    INNER JOIN TABLE2 LCS ON  CONDITION
    WHERE CONDITION


    $sql="从basic_tbl中删除,education_tblpersonal_tbladdress_tbldepartment_tbl。使用以东十一〔4〕、以东十一〔5〕,personal_tbladdress_tbldepartment_tbl。哪里b_id=e_id=p_id=a_id=d_id='.$id.''";$rs=mysqli_查询($con,$sql);