Tsql T-SQL:通过联接选择要删除的行

Tsql T-SQL:通过联接选择要删除的行,tsql,join,Tsql,Join,情景: 假设我有两张桌子,表A和表B。TableB的主键是单列(BId),是TableA中的外键列 在我的情况下,我想删除TableA中与TableB中特定行链接的所有行:我可以通过连接来完成吗?是否删除从联接中拉入的所有行 DELETE FROM TableA FROM TableA a INNER JOIN TableB b ON b.BId = a.BId AND [my filter condition] 或者我是被迫这样做的: DELETE FR

情景:

假设我有两张桌子,表A和表B。TableB的主键是单列(BId),是TableA中的外键列

在我的情况下,我想删除TableA中与TableB中特定行链接的所有行:我可以通过连接来完成吗?是否删除从联接中拉入的所有行

DELETE FROM TableA 
FROM
   TableA a
   INNER JOIN TableB b
      ON b.BId = a.BId
      AND [my filter condition]
或者我是被迫这样做的:

DELETE FROM TableA
WHERE
   BId IN (SELECT BId FROM TableB WHERE [my filter condition])
我提出这个问题的原因是,在我看来,第一种选择在处理较大的表时会更加有效

谢谢

DELETE TableA
FROM   TableA a
       INNER JOIN TableB b
               ON b.Bid = a.Bid
                  AND [my filter condition] 
应该可以

是的,你可以。例如:

DELETE TableA 
FROM TableA AS a
INNER JOIN TableB AS b
ON a.BId = b.BId
WHERE [filter condition]

我会使用这种语法

Delete a 
from TableA a
Inner Join TableB b
on  a.BId = b.BId
WHERE [filter condition]

MySQL中几乎相同,但必须在单词“DELETE”之后使用表别名:


正在尝试使用access数据库执行此操作,发现我需要在删除后立即使用a.*

DELETE a.*
FROM TableA AS a
INNER JOIN TableB AS b
ON a.BId = b.BId
WHERE [filter condition]

上述语法在Interbase 2007中不起作用。相反,我不得不使用类似于:

DELETE FROM TableA a WHERE [filter condition on TableA] 
  AND (a.BId IN (SELECT a.BId FROM TableB b JOIN TableA a 
                 ON a.BId = b.BId 
                 WHERE [filter condition on TableB]))

(注意Interbase不支持别名的AS关键字)

假设您有两个表,一个是主表(如Employees),另一个是子表(如Dependents),您希望删除Dependents表中无法与主表中的任何行进行键合的所有数据行

delete from Dependents where EmpID in (
select d.EmpID from Employees e 
    right join Dependents d on e.EmpID = d.EmpID
    where e.EmpID is null)

这里要注意的一点是,您只是首先从连接中收集一个empid的“数组”,然后使用该empid集对Dependents表执行删除操作

在SQLite中,唯一有效的是类似于beauXjames的答案

似乎归结到这一点
从表1中删除,其中表1.col1位于(一些临时表)

通过选择并连接两个表,您可以根据要删除表1中记录的条件筛选此临时表。您可以运行此查询:

从表A中删除
从…起
表a,表b
哪里
a、 投标=b.投标
及
[我的过滤条件]
我在用这个

DELETE TableA 
FROM TableA a
INNER JOIN
TableB b on b.Bid = a.Bid
AND [condition]
@TheTXI方法也很好,但我阅读了答案和注释,发现必须回答的一件事是在WHERE子句中使用条件或作为连接条件。所以我决定测试它并编写一个代码片段,但没有发现它们之间有什么有意义的区别。你们可以在这里看到sql脚本,重要的一点是,我更喜欢用commnet编写,因为这不是确切的答案,但它很大,不能放在注释中,请原谅

Declare @TableA  Table
(
  aId INT,
  aName VARCHAR(50),
  bId INT
)
Declare @TableB  Table
(
  bId INT,
  bName VARCHAR(50)  
)

Declare @TableC  Table
(
  cId INT,
  cName VARCHAR(50),
  dId INT
)
Declare @TableD  Table
(
  dId INT,
  dName VARCHAR(50)  
)

DECLARE @StartTime DATETIME;
SELECT @startTime = GETDATE();

DECLARE @i INT;

SET @i = 1;

WHILE @i < 1000000
BEGIN
  INSERT INTO @TableB VALUES(@i, 'nameB:' + CONVERT(VARCHAR, @i))
  INSERT INTO @TableA VALUES(@i+5, 'nameA:' + CONVERT(VARCHAR, @i+5), @i)

  SET @i = @i + 1;
END

SELECT @startTime = GETDATE()

DELETE a
--SELECT *
FROM @TableA a
Inner Join @TableB b
ON  a.BId = b.BId
WHERE a.aName LIKE '%5'

SELECT Duration = DATEDIFF(ms,@StartTime,GETDATE())

SET @i = 1;
WHILE @i < 1000000
BEGIN
  INSERT INTO @TableD VALUES(@i, 'nameB:' + CONVERT(VARCHAR, @i))
  INSERT INTO @TableC VALUES(@i+5, 'nameA:' + CONVERT(VARCHAR, @i+5), @i)

  SET @i = @i + 1;
END

SELECT @startTime = GETDATE()

DELETE c
--SELECT *
FROM @TableC c
Inner Join @TableD d
ON  c.DId = d.DId
AND c.cName LIKE '%5'

SELECT Duration    = DATEDIFF(ms,@StartTime,GETDATE())
Declare@TableA表
(
国际援助,
阿纳姆·瓦尔查尔(50岁),
投标整数
)
声明@TableB表
(
国际招标,
bName VARCHAR(50)
)
声明@TableC表
(
cId INT,
cName VARCHAR(50),
不完整
)
声明@Table表
(
没有INT,
dName VARCHAR(50)
)
声明@StartTime DATETIME;
选择@startTime=GETDATE();
声明@i INT;
设置@i=1;
而@i<1000000
开始
插入@TableB值(@i,'nameB:'+CONVERT(VARCHAR,@i))
插入@TableA值(@i+5,'nameA:'+CONVERT(VARCHAR,@i+5),@i)
设置@i=@i+1;
结束
选择@startTime=GETDATE()
删除
--挑选*
来自@TableA
表b中的内部连接
a.投标=b.投标
其中a.aName类似于“%5”
选择Duration=DATEDIFF(ms,@StartTime,GETDATE())
设置@i=1;
而@i<1000000
开始
插入到@table值(@i,'nameB:'+CONVERT(VARCHAR,@i))中
插入@TableC值(@i+5,'nameA:'+CONVERT(VARCHAR,@i+5),@i)
设置@i=@i+1;
结束
选择@startTime=GETDATE()
删除c
--挑选*
来自@TableC
内连接@TableD
在c.DId=d.DId上
和类似“%5”的c.cName
选择Duration=DATEDIFF(ms,@StartTime,GETDATE())
如果你能从这个脚本中得到好的理由,或者写另一个有用的,请分享。感谢并希望能提供帮助。

更简单的方法是:

删除表a
从表B
其中TableA.ID=TableB.ID
将DML查询与联接的使用降至最低。您应该能够使用上面提到的子查询来执行大部分DML查询


通常,只有在需要在2个或更多表中选择列或按列分组时,才应使用联接。如果只触摸多个表来定义填充,请使用子查询。对于删除查询,请使用相关子查询。

我在连接上使用And[my filter condition],而不是Where子句。我想这两种方法都可以,但是联接的过滤条件会限制联接的结果。一个问题。为什么我们需要写“从中删除表格”而不是“从中删除”?我知道它只在这种情况下有效,但为什么呢?我想是因为您必须指明要从哪个表中删除记录。我刚刚用
DELETE TableA,TableB…
的语法运行了一个查询,实际上从这两个表中删除了相关记录。不错。在PostgreSQL语法中,join不起作用,但可以使用“using”关键字<代码>使用TableB b从TableA中删除,其中b.Bid=a.Bid和[my filter condition]
在MySQL中,您会得到一个错误“MULTI-DELETE中的未知表'TableA',这是因为您为TableA(a)声明了一个别名。小调整:
deleteafromtablea a内部连接TableB on b.Bid=a.Bid和[my filter condition]
我也喜欢这种语法,似乎在逻辑上更合理一些。此外,我知道您可以使用相同类型的语法进行更新。我也更喜欢使用这种语法,因为在删除之后,表别名的位置对我来说总是更直观地显示要删除的内容。事实上,我也更喜欢这种语法。特别是在我需要实际加入同一个表的情况下(例如,删除重复记录)。在这种情况下,我需要为我要删除的“side”使用一个别名,这个语法非常清楚我要从重复的别名中删除。我更喜欢通过别名引用第一行中的表。即“删除a”而不是“删除表格a”。在您将表与自身联接的情况下,它会清楚地表明您要删除哪一侧。Fr
Declare @TableA  Table
(
  aId INT,
  aName VARCHAR(50),
  bId INT
)
Declare @TableB  Table
(
  bId INT,
  bName VARCHAR(50)  
)

Declare @TableC  Table
(
  cId INT,
  cName VARCHAR(50),
  dId INT
)
Declare @TableD  Table
(
  dId INT,
  dName VARCHAR(50)  
)

DECLARE @StartTime DATETIME;
SELECT @startTime = GETDATE();

DECLARE @i INT;

SET @i = 1;

WHILE @i < 1000000
BEGIN
  INSERT INTO @TableB VALUES(@i, 'nameB:' + CONVERT(VARCHAR, @i))
  INSERT INTO @TableA VALUES(@i+5, 'nameA:' + CONVERT(VARCHAR, @i+5), @i)

  SET @i = @i + 1;
END

SELECT @startTime = GETDATE()

DELETE a
--SELECT *
FROM @TableA a
Inner Join @TableB b
ON  a.BId = b.BId
WHERE a.aName LIKE '%5'

SELECT Duration = DATEDIFF(ms,@StartTime,GETDATE())

SET @i = 1;
WHILE @i < 1000000
BEGIN
  INSERT INTO @TableD VALUES(@i, 'nameB:' + CONVERT(VARCHAR, @i))
  INSERT INTO @TableC VALUES(@i+5, 'nameA:' + CONVERT(VARCHAR, @i+5), @i)

  SET @i = @i + 1;
END

SELECT @startTime = GETDATE()

DELETE c
--SELECT *
FROM @TableC c
Inner Join @TableD d
ON  c.DId = d.DId
AND c.cName LIKE '%5'

SELECT Duration    = DATEDIFF(ms,@StartTime,GETDATE())
DELETE FROM table1
where id IN 
    (SELECT id FROM table2..INNER JOIN..INNER JOIN WHERE etc)