【问题标题】:SQL Server : multiple WHERE NOT EXISTS clausesSQL Server:多个 WHERE NOT EXISTS 子句
【发布时间】:2019-05-18 06:49:22
【问题描述】:

Load_Charges_IMPORT 查询中有大约 2600 行没有插入到Load_Charges 查询中。

我试图确保没有添加重复的主键条目。主键在Load_Charges 查询中建立为复合键(收费说明 + 收费金额)。 Load_Charges_IMPORT 查询中未设置任何键,并且此数据是从 Excel 文档中导入的。

当我知道Load_Charges_IMPORT 中有 2600 多行时,您能否告诉我我的代码是否有问题以及为什么我会收到0 row(s) affected 的响应。

INSERT INTO Load_Charges
    SELECT *
    FROM Load_Charges_IMPORT
    WHERE 
        NOT EXISTS (SELECT [Load ID]
                    FROM Load_Charges
                    WHERE Load_Charges_IMPORT.[Load ID] = Load_Charges.[Load ID])
        AND NOT EXISTS (SELECT [Charge Description]
                        FROM Load_Charges
                        WHERE Load_Charges_IMPORT.[Charge Description] = Load_Charges.[Charge Description])
        AND NOT EXISTS (SELECT [Charged Amount] 
                        FROM Load_Charges
                        WHERE Load_Charges_IMPORT.[Charged Amount] = Load_Charges.[Charged Amount]);

【问题讨论】:

  • 至少您的not exists 条件之一必须排除超出您预期的内容。通过单独测试每个not exists 条件进行调试,然后更改为exists 条件以查看哪些行匹配(因此未导入)。一旦你识别出它们,你就会看到你的重复逻辑在哪里不正确——我们无法告诉你。
  • 您希望通过发布的代码导入但未导入的阶段表中的行的示例是什么?

标签: sql sql-server tsql not-exists


【解决方案1】:

解决此问题的另一种方法是使用一系列LEFT JOINs,并带有一个排除任何匹配记录的WHERE 子句。

这是一种较短的语法,并且避免使用子查询。

INSERT INTO Load_Charges
SELECT imp.*
FROM 
    Load_Charges_IMPORT imp
    LEFT JOIN Load_Charges load1 ON load1.[Load ID] = imp.[Load ID]
    LEFT JOIN Load_Charges load2 ON load2.[Charge Description] = imp.[Charge Description]
    LEFT JOIN Load_Charges load3 ON load3.[Charged Amount]= imp.[Charged Amount]
WHERE load1.[Load ID] IS NULL AND load2.[Load ID] IS NULL AND load3.[Load ID] IS NULL
;

NB :这假定 [Load ID] 是 Load_Charges 表中的不可为空的字段。如果不是,则可以在WHERE 子句中使用任何其他不可为空的字段。

【讨论】:

  • 您刚刚将SELECT * 返回的列增加了四倍:)
  • @DaveCullum :是的,您是对的,感谢您的检查...已修复
【解决方案2】:

您的 EXISTS 子句排除任何一个条件为 TRUE 的所有行,而不仅仅是所有条件都为 TRUE 的行。试试这个:

INSERT INTO Load_Charges

SELECT *

FROM Load_Charges_IMPORT

WHERE NOT EXISTS (
    SELECT * 
    FROM Load_Charges 
    WHERE Load_Charges_IMPORT.[Load ID]=Load_Charges.[Load ID]
    AND Load_Charges_IMPORT.[Charge Description]=Load_Charges.[Charge Description]
    AND Load_Charges_IMPORT.[Charged Amount]=Load_Charges.[Charged Amount]);

【讨论】:

  • 我会重构它以使用别名'并将NOT EXISTS (SELECT *更改为NOT EXISTS (SELECT 1
  • 请注意,这需要相同的行匹配,而原始查询不需要。
  • @DaveCullum - 我也会重构使用别名,但不是每个人都喜欢别名表。此外,Exists 调用中的 SELECT * 和 SELECT 1 在最新版本的 SQL Server 中执行完全相同的功能。区分是不必要的。
  • @LaughingVergil:为什么没有人使用select 0select 'foo' 而不是select 1?我更喜欢select 1/0 来迷惑读者:-)
  • 哈!抱歉,我知道执行计划是一样的……都是为了可读性和精简;至少对我而言,在您的脑海中阅读“全选”与“全选 1”意味着数据在代码的下游或其他地方使用。 @LaughingVergil 我无法理解一个会对化名嗤之以鼻的人的想法! :)
猜你喜欢
  • 2013-04-17
  • 2016-01-09
  • 2015-09-04
  • 1970-01-01
  • 2012-05-16
  • 2013-02-10
  • 1970-01-01
  • 1970-01-01
  • 2018-01-28
相关资源
最近更新 更多