使用“NOT IN”子句查询删除一个表中的记录,以检查多个表。这个查询可以更简化吗?

Posted

技术标签:

【中文标题】使用“NOT IN”子句查询删除一个表中的记录,以检查多个表。这个查询可以更简化吗?【英文标题】:Query Deleting Records in One Table by using "NOT IN " clause to check with multiple table. Can this query be more simplified? 【发布时间】:2020-12-23 11:00:34 【问题描述】:

现在我正在使用下面的查询

 string myQry = "DELETE FROM myMainTbl AS a WHERE
    a.id NOT IN(SELECT b.mainid FROM mySubTbl_1 AS b WHERE b.mainid = a.id GROUP BY b.mainid HAVING MAX(b.sttime) > @mydate)
    AND
    a.id NOT IN(SELECT c.mainid FROM mySubTbl_2 AS c WHERE c.mainid = a.id GROUP BY c.mainid HAVING MAX(c.sttime) > @mydate)
    AND
    a.id NOT IN(SELECT d.mainid FROM mySubTbl_3 AS d WHERE d.mainid = a.id GROUP BY d.mainid HAVING MAX(d.sttime) > @mydate)
   AND
   a.id NOT IN(SELECT e.mainid FROM mySubTbl_4 AS e WHERE e.mainid = a.id GROUP BY e.mainid HAVING MAX(e.sttime) > @mydate)
   AND
   a.id NOT IN(SELECT f.mainid FROM mySubTbl_5 AS f WHERE f.mainid = a.id GROUP BY f.mainid HAVING MAX(f.sttime) > @mydate)";

能不能再简化一点?

【问题讨论】:

简短回答:你不能。 MS Access 没有完全实现 SQL-92(甚至是 Access 2019!)并且它不支持在 DELETE 中使用 JOIN,请参见此处:***.com/questions/5585732/… 据我所知,MS Access 不支持 T-SQL 风格的命名参数(例如@mydate),因此您的查询无论如何都不会工作。 请确认您在 MS Access 中使用 JET Red 或 ACE,或者您是否使用 Access 作为 SQL Server 或其他 ODBC/OLE-DB 数据库的前端。 看起来您想要防止无意删除外键关系中的主体实体。做到这一点的方法是强制执行 FK 约束 - 这样您就不需要过滤 DELETE 语句:相反,如果 DBMS 违反约束,它将简单地抛出一个错误。 【参考方案1】:

您可以将其重写为NOT EXISTS,这样就不必担心组和聚合,并合并数据以简化查询:

DELETE 
FROM myMainTbl AS a 
WHERE
    NOT EXISTS(
        SELECT 1 FROM (
            SELECT mainid, sttime
            FROM mySubTbl_1 
            UNION ALL
            SELECT mainid, sttime
            FROM mySubTbl_2 
            UNION ALL
            SELECT mainid, sttime
            FROM mySubTbl_3
            UNION ALL
            SELECT mainid, sttime
            FROM mySubTbl_4 
            UNION ALL
            SELECT mainid, sttime
            FROM mySubTbl_5
        ) b
        WHERE b.mainid = a.id AND sttime > @mydate
    )

这在语义上对我来说也更清楚,您想删除其中一个子表中不存在相关行且时间大于您的参数的所有行。

【讨论】:

非常感谢,Union 运行起来非常简单、快捷。【参考方案2】:

我推荐NOT EXISTS 而不是NOT IN。这看起来像:

NOT EXISTS (SELECT 1 FROM mySubTbl_1 AS b WHERE b.mainid = a.id AND b.sttime > @mydate)

如果在日期之后不存在匹配行,则最大值也不存在。

然后,您可以添加索引来优化此查询:mySubTbl_1(mainid, sttime)

根据您的查询,创建索引并使用:

DELETE FROM myMainTbl AS a
    WHERE NOT EXISTS (SELECT b.mainid FROM mySubTbl_1 AS b WHERE b.mainid = a.id AND b.sttime > @mydate) AND
          NOT EXISTS (SELECT c.mainid FROM mySubTbl_2 AS c WHERE c.mainid = a.id AND c.sttime > @mydate) AND
          NOT EXISTS (SELECT d.mainid FROM mySubTbl_3 AS d WHERE d.mainid = a.id AND d.sttime > @mydate) AND
          NOT EXISTS (SELECT e.mainid FROM mySubTbl_4 AS e WHERE e.mainid = a.id AND e.sttime > @mydate) AND
          NOT EXISTS (SELECT f.mainid FROM mySubTbl_5 AS f WHERE f.mainid = a.id AND f.sttime > @mydate)";

【讨论】:

以上是关于使用“NOT IN”子句查询删除一个表中的记录,以检查多个表。这个查询可以更简化吗?的主要内容,如果未能解决你的问题,请参考以下文章

将另一个表中的逐行值转换为字符串并将其插入到 SQL 中的 NOT IN 子句中

Sql server not in优化

踩坑记录Mysql查询使用not in会出现意外返回空的情况

踩坑记录Mysql查询使用not in会出现意外返回空的情况

踩坑记录Mysql查询使用not in会出现意外返回空的情况

踩坑记录Mysql查询使用not in会出现意外返回空的情况