【问题标题】:How do I delete from multiple tables using INNER JOIN in SQL server如何在 SQL Server 中使用 INNER JOIN 从多个表中删除
【发布时间】:2025-12-05 15:50:02
【问题描述】:

在 MySQL 中你可以使用语法

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

我如何在 SQL Server 中做同样的事情?

【问题讨论】:

    标签: sql sql-server tsql


    【解决方案1】:

    您可以利用此示例中的“已删除”伪表。比如:

    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;
    

    显然,您可以执行“输出已删除”。在第二次删除时,如果您需要为第三张表加入一些东西。

    附带说明一下,您还可以在插入语句中执行插入。*,在更新语句中同时插入。* 和删除。*。

    编辑: 另外,您是否考虑过在 table1 上添加触发器以从 table2 + 3 中删除?您将处于一个隐式事务中,并且还可以使用“inserted.”和“deleted.”伪表。

    【讨论】:

    • 只从 table1 WHERE id = x 中删除然后从下一个表中删除而不是使用内部连接并遍历所有这些额外的文本会更好吗?基本上,跳过内部连接我只需要 2 个简单的查询......或者这种方法更有效吗?
    • 我认为这取决于您的 where 子句有多复杂。对于复杂的,这会更好,因为它只发生一次。但是对于影响大量行的更简单的 where 子句,您的建议可能会更有效,因为它不必在表变量中保存许多 id。
    • @JohnGibb,这个答案是如何工作的?你能解释一下这个答案,以便 MySQL 开发人员能够理解吗?
    • @Pacerier 我对 MySQL 不是很熟悉。这个想法是第一次删除只是从 table1 中删除,但它将被删除的 ID 保存到变量中。随后的两条语句如何使用该变量从表 2 和表 3 中删除关联的行。
    • @JohnGibb,现在那就是清楚了。您应该将其包含在答案中。
    【解决方案2】:
    1. 您始终可以对表的关系设置级联删除。

    2. 您可以将多个删除操作封装在一个存储过程中。

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

    【讨论】:

    • 绝对可以在连接语句中删除,我只想一次从多个表中删除。
    • 错误答案,join可以和delete一起使用
    • ad 1.) 这不是真的,它可能并不总是可能的。在某些情况下,您无法设置级联删除,例如循环或多个级联路径。 (例如见*.com/a/3548225/108374
    【解决方案3】:

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

    来自示例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;
    

    【讨论】:

    • 示例 D:从 Sales.SalesPersonQuotaHistory 中删除,从 Sales.SalesPersonQuotaHistory AS spqh INNER JOIN Sales.SalesPerson AS sp ON spqh.BusinessEntityID = sp.BusinessEntityID WHERE sp.SalesYTD > 2500000.00;
    【解决方案4】:

    删除主表部分记录和两个明细表对应记录的示例:

    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
    

    【讨论】:

    • 你能用SELECT INTO #DeleteIds代替CREATE TABLE 'DeleteIds,然后是INSERT INTO 'DeleteIds...吗?
    【解决方案5】:

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

    【讨论】:

    • 我希望我不必这样做,我想我必须将 ID 选择到临时表中,因为关系不是父子关系。一旦一个表中的行消失,就无法获取其他行。
    【解决方案6】:

    只是想知道......这在 MySQL 中真的可能吗?它会删除t1和t2吗?或者我只是误解了这个问题。

    但是如果你只想删除带有多个连接条件的table1,只是不要为你要删除的表加上别名

    这个:

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

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

    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 提示,我不得不按照这些思路调整 SQL。
    【解决方案7】:

    在 SQL Server 中,无法使用连接从多个表中删除记录。 所以你必须先从子级删除,然后再删除父级。

    【讨论】:

    • 类似这样:DELETE ChildTable Where id=@id(新行) DELETE ParentTable Where id=@id? (ID 是 PK 和 FK)
    【解决方案8】:

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

    声明 @user Table(keyValue int , someString varchar(10)) 插入@user 值(1,'1 值') 插入@user 值(2,'2 值') 插入@user 值(3,'3 值') 声明@password 表(keyValue int,详细信息 varchar(10)) 插入@password 值(1,'1 密码') 插入@password 值(2,'2密码') 插入@password 值(3,'3 密码') --删除前 select * from @password a 内连接 @user b a.keyvalue = b.keyvalue select * into #deletedID from @user where keyvalue=1 - 这与输出示例类似 删除键值 =1 的 @user 删除键值所在的@password(从#deletedid 中选择键值) --删除后-- select * from @password a 内连接 @user b a.keyvalue = b.keyvalue

    【讨论】:

      【解决方案9】:

      一切都已被指出。只需在父级table 上使用DELETE ON CASCADE 或从child-table 中删除,然后再使用parent

      【讨论】:

      • 从子表删除到父表是什么意思?您是指使用问题或上述答案中显示的连接技术吗?
      【解决方案10】:

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

      【讨论】:

        【解决方案11】:

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

        --*** 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;
        

        【讨论】:

          【解决方案12】:
          DELETE     TABLE1 LIN
          FROM TABLE1 LIN
          INNER JOIN TABLE2 LCS ON  CONDITION
          WHERE CONDITION
          

          【讨论】:

          • 它不会从两个或多个表中删除。请理解问题
          【解决方案13】:

          $sql="删除basic_tbl,education_tbl, personal_tbl,address_tbl,department_tbl 使用 basic_tbl,education_tbl, personal_tbl,address_tbl,department_tbl 在哪里 b_id=e_id=p_id=a_id=d_id='".$id."' "; $rs=mysqli_query($con,$sql);

          【讨论】:

          • 请修正您的格式并简要说明您的代码工作的原因。