【问题标题】:Delete unmatched records in Access在 Access 中删除不匹配的记录
【发布时间】:2011-04-06 15:35:57
【问题描述】:

我在 Access 数据库中有一个表,其中的记录可以从其他两个表中的任何一个中引用。如果其他任何一个都没有引用它们,我需要从该表中删除记录。 到目前为止,我最好的解决方案是创建一个子查询来返回引用记录的 id 并从删除查询中引用子查询。 (子查询必须分开,因为 Access 不允许在嵌套子查询中使用 UNION。)

所以...
选择查询:

SELECT TableB.id FROM TableB INNER JOIN TableA ON TableB.id = TableA.id  
UNION  
SELECT TableC.id FROM TableC INNER JOIN TableA ON TableC.id = TableA.id  

删除查询:

 DELETE * FROM TableA WHERE id NOT IN (SELECT * FROM SelectQuery)

这太慢了……一定有更好的方法吗?

我试图避免将布尔值“Used”字段添加到 TableA ...

【问题讨论】:

  • 最后我咬紧牙关,在表 A 中添加了一个 Used 列。使用两个单独的查询更新了 Used 列,每个查询一个用于其他表。然后删除 Used=No 的所有记录。将执行时间从 56 分钟减少到 3 秒。
  • 56 分钟?即使您没有索引并且正在执行三个完整的表扫描,我也很难相信它会花费那么长时间?整个表的嵌套子查询是否在每条记录中重复?
  • 好吧,UNION 不能使用索引。

标签: sql ms-access


【解决方案1】:

@Matthew PK 建议使用两个 NOT IN 子查询,这在理论上是个好主意,但正如我在评论中观察到的,Jet/ACE 对 NOT IN 和 NOT EXISTS 的优化很差,并且通常不会使用两边的索引的比较。我想知道是否需要子查询:

  DELETE *
  FROM (TableA LEFT JOIN TableB ON TableA.ID = TableB.ID) LEFT JOIN TableC ON TableA.ID = TableC.ID
  WHERE TableB.ID Is Null AND TableC.ID Is Null;

这肯定会使用您的索引。如果需要子查询,您可以将 TableB 和 TableC 替换为相关的子查询。

【讨论】:

  • 外连接结合空检查绝对是实现“不在”逻辑的最佳方式。 +1。
  • 我必须将第一行更改为 Delete TableA.* 才能让它在 Access 查询中为我工作
【解决方案2】:

为什么不这样:

DELETE FROM TableA 
WHERE 
    id NOT IN (SELECT id FROM TableB)
AND
    id NOT IN (SELECT id FROM TableC)

?

【讨论】:

  • 嗯。如果我没有按照我在上面的评论中描述的那样工作,我可能会尝试过。它现在只是学术兴趣,我没有时间检查它。无论如何,谢谢你的想法。
  • 问题在于 Jet/ACE 对 NOT IN 和 NOT EXISTS 的优化很差,因此它不一定会利用比较两边的索引。
  • @David,我同意,你的回答比我的好。
【解决方案3】:

是否可以根据您的 SelectQuery 创建一个新表,删除原始表并将新表重命名为原始名称?

【讨论】:

    【解决方案4】:
    /* delete more records */
    
    DELETE FROM table1
    WHERE NOT EXISTS
    (SELECT field FROM table2 WHERE table2.field = table1.field)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-15
      相关资源
      最近更新 更多