【问题标题】:Elegant way to delete rows which are not referenced by other table删除其他表未引用的行的优雅方法
【发布时间】:2010-07-22 19:57:46
【问题描述】:

我有两个表(Tasks 和 Timeentries),它们通过外键连接(TimeEntries.TaskID 引用 Tasks.ID)

现在我想从 Tasks 中删除 TimeEntries 表未引用的所有行。我认为这应该可行:

DELETE FROM Tasks WHERE ID not IN (SELECT TaskID FROM TimeEntries)

但它会影响 0 行,即使 Tasks 表中有很多未引用的行。

这里可能有什么问题?当然,我可以编写一个迭代所有行的 SP,但似乎这可以在一个内衬中完成。

我猜这是睡眠时间下溢错误之一。请帮忙!

【问题讨论】:

  • 如果只单独运行 SELECT 子查询,会得到预期的结果吗?

标签: sql-server tsql sql-server-2008


【解决方案1】:

not in 有一个臭名昭著的陷阱。基本上,id not in (1,2,3) 是以下的简写:

id <> 1 and id <> 2 and id <> 3

现在,如果您的 TimeEntries 表包含任何具有 TaskIDnull 的行,则 not in 将转换为:

ID <> null and ID <> 1 and ID <> 2 AND ...

null 比较的结果始终是unknown。由于unknown 在 SQL 中不成立,where 子句会过滤掉所有行,最终什么都不会删除。

一个简单的解决方法是在子查询中添加一个 where 子句:

DELETE FROM Tasks 
WHERE  ID not IN 
       (
       SELECT  TaskID 
       FROM    TimeEntries 
       WHERE   TaskID is not null
       )

【讨论】:

  • 您对如何解决这个问题有什么建议吗?
  • @DOK:当然,答案中添加了一种方法。 SQLMenace 发布了另一个好消息
  • 优秀的答案。非常感谢!
  • 确实如此。这可能很旧,但我在谷歌上找到了它,我必须说我喜欢你解释它的方式。非常清楚!感谢您的帮助!
【解决方案2】:

一种方式,这将解决您在使用空值时遇到的“问题”(有关更多信息,请参见下面的链接)

DELETE FROM Tasks 
WHERE NOT EXISTS (SELECT 1 FROM TimeEntries 
                  WHERE TimeEntries.TaskID  = Tasks.ID )

要了解您遇到的问题,请查看Select all rows from one table that don't exist in another table

【讨论】:

  • 我猜这个答案更优雅。
【解决方案3】:

由于您运行的是 SQL 2008,因此您可以使用漂亮的新合并语法。

MERGE Tasks AS target
USING TimeEntries as Source ON (Target.TaskID=Source.TaskID)
WHEN NOT MATCHED BY Source THEN DELETE; 

【讨论】:

  • +1:在这种情况下有点矫枉过正,但了解合并命令肯定很有用。我什至不知道有这样的东西存在。
  • 为什么你认为这是矫枉过正?它非常适合这样的任务(匹配表之间的行)。
  • 与以前的解决方案相比,它的性能如何?它是否有任何优势,或者这是执行此类操作的受支持方式?谢谢
  • 必须匹配两列,这是唯一对我有用的解决方案。
【解决方案4】:

我知道这是旧的,但我想知道为什么没有人提到 here 中描述的删除查询。所以,供参考:

DELETE FROM Tasks
FROM Tasks LEFT OUTER JOIN
    TimeEntries ON TimeEntries.TaskID = Tasks.ID
WHERE TimeEntries.TaskID IS NULL;

此语法与 ISO 不兼容,因此仅适用于 T-SQL。

【讨论】:

    【解决方案5】:
      Delete FROM Tasks 
           WHERE not Exists 
              (SELECT 'X' FROM TimeEntries where TimeEntries.TaskID  = Tasks.ID)
    

    上面的 SQL 应该删除时间条目表中不存在 Task.ID 的任务中的所有行。我会先将其作为 select 语句运行以进行测试:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-05-13
      • 1970-01-01
      • 2020-05-20
      • 1970-01-01
      • 2015-03-18
      • 2015-12-12
      • 2011-11-30
      相关资源
      最近更新 更多