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


117

在MySQL中,您可以使用语法

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

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

Answers:


119

在此示例中,您可以利用“已删除”伪表。就像是:

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;

显然,您可以执行“已删除输出”。如果您需要加入第三张表的内容,也可以在第二张表上删除。

附带说明一下,您也可以在插入语句上执行insert。*,在更新语句上同时进行insert。*和Deleted。*。

编辑: 另外,您是否考虑过在table1上添加触发器以从table2 + 3中删除?您将处于隐式事务中,并且还将具有“插入的”和“删除的 ”伪表。


2
最好只是从table1 WHERE id = x中删除,然后从下一个表中删除,而不是使用内部联接并遍历所有这些额外的文本?基本上,跳过内部联接,我只需要2个简单的查询...。还是该方法更有效?
Colandus

我认为这取决于where子句的复杂程度。对于复杂的用户,这样做会更好,因为它只会发生一次。但是对于影响很多行的更简单的where子句,您的建议可能会更有效,因为它不必在表变量中包含很多id。
John Gibb 2013年

@JohnGibb,此答案如何起作用?您可以解释这个答案,以便MySQL开发人员可以理解吗?
Pacerier,2015年

@Pacerier我对MySQL不是很熟悉。这个想法是,第一次删除仅从table1中删除,但是它将已删除的ID保存到变量中。随后的两个语句如何使用这个变量,从表2和表3中删除相关的行
约翰·吉布

@JohnGibb,现在清楚。您应该将其包括在答案中。
和平者

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

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

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


3
肯定可以在join语句中删除,我只想一次从多个表中删除。
拜伦·惠特洛克

错误的答案,联接可以与删除一起使用
rboarman 2010年

广告1.)事实并非如此,并非总是可能。在某些情况下,您无法设置级联删除,例如循环或多个级联路径。(例如,请参见stackoverflow.com/a/3548225/108374)–
汤姆·帕索里克(TomPažourek

15

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

这里的例子:

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

3
示例D:从Sales.SalesPersonQuotaHistory从Sales.SalesPersonQuotaHistory AS spqh内联接Sales.SalesPerson AS sp ON在spqh.BusinessEntityID = sp.BusinessEntityID上,sp.SalesYTD> 2500000.00;
标记A

11

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

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

1
您能使用SELECT INTO #DeleteIds而不是CREATE TABLE 'DeleteIds跟随INSERT INTO 'DeleteIds...吗?
卡托

9

只是想知道..在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。
Pauk)

7

基本上,不需要在事务中做出三个删除语句,首先是孩子,然后是父母。如果这不是一次性的事情,并且不与任何现有触发器设置冲突,那么设置级联删除是一个好主意。


我希望不必这样做,我想我必须在临时表中选择ID,因为这种关系不是亲子关系。一旦一个表中的行消失了,就无法获取其他行。
拜伦·惠特洛克

3

在SQL Server中,无法使用联接删除多个表。因此,您必须先从子级删除,然后再删除父级表单。


2

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

声明@user表(keyValue int,someString varchar(10))
插入@user
值(1,'1值')

插入@user
values(2,'2 value')

插入@user
值(3,'3值')

声明@password表(keyValue int,详细信息varchar(10))
插入@password
值(1,'1密码')
插入@password
值(2,'2密码')
插入@password
值(3,'3密码')

        -删除前
  选择* from @password a内部联接@user b
                在a.keyvalue = b.keyvalue上
  选择*到@user的#deletedID中,其中键值= 1-这类似于输出示例
  删除@user,其中keyvalue = 1
  删除@password其中的键值(从#deletedid中选择键值)

  -删除后-
  选择* from @password a内部联接@user b
                在a.keyvalue = b.keyvalue上


2

一切都已指出。只需DELETE ON CASCADE在父级上使用table或从中删除child-table即可parent


从子表删除到父表是什么意思?您是说使用有问​​题或上述答案的连接技术吗?
Imran Faruqi

1

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


0

根据约翰·吉布(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;

-3
DELETE     TABLE1 LIN
FROM TABLE1 LIN
INNER JOIN TABLE2 LCS ON  CONDITION
WHERE CONDITION

它不会从两个或多个表中删除。请理解问题
Kamran Shahid

-5

$的SQL = “DELETE FROM basic_tbleducation_tblpersonal_tbladdress_tbldepartment_tbl 使用 basic_tbleducation_tblpersonal_tbladdress_tbldepartment_tbl WHERE b_id= e_id= p_id= a_id= d_id=”“ $ ID。””“; $ rs = mysqli_query($ con,$ sql);


请修正您的格式,并简要说明您的代码为何起作用。
Bryan Herbst
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.