【问题标题】:WHERE clause using values that could be NULL使用可能为 NULL 的值的 WHERE 子句
【发布时间】:2021-05-12 10:05:50
【问题描述】:

我需要这样做:

DECLARE @firstname VARCHAR(35)
DECLARE @lastname VARCHAR(35)

SELECT *
FROM Customers 
WHERE Firstname = @firstname AND Lastname = @lastname

问题是@firstname@lastname 有时可能是NULL。在这些情况下,上面的查询将无法找到匹配的行,因为NULL 永远不会等于NULL

如果这些变量之一是NULL,如果数据库中的相应值也是NULL,我想返回一个匹配项。但是,当然,SQL Server 使用IS 来比较NULL。如果在上例中任一值为NULL,则不视为匹配。

有没有办法做到这一点?

【问题讨论】:

  • @Charlieface:不是这样。我接受的答案回答得更好。
  • @JonathanWood 实际上 Charlieface 的建议 is 比我的 (IMO) 好。更加简单和可扩展。
  • 如你所愿。我发现我的版本不那么麻烦。 @DaleK 我认为在大多数情况下性能并没有太大的不同,只是更加整洁,尤其是在进行大量比较时。
  • @Charlieface 说句公道话,我不认为这是一个骗子,OP 在问 如何 这样做,而建议的骗子在问 如何改进.

标签: sql sql-server tsql null


【解决方案1】:

只需使用 AND/OR 逻辑,例如

SELECT *
FROM Customers
WHERE ((Firstname IS NULL AND @firstname IS NULL) OR Firstname = @firstname)
AND ((Lastname IS NULL AND @lastname IS NULL) OR Lastname = @lastname);

【讨论】:

【解决方案2】:

您可以在相关子查询中利用 INTERSECT 来执行此操作。这是因为基于集合的操作比较 NULLs 是相等的。

编译器会将automatically compile this 降低到IS 比较,应该不会有任何性能损失。

DECLARE @firstname VARCHAR(35)
DECLARE @lastname VARCHAR(35)

SELECT *
FROM Customers c
WHERE EXISTS (SELECT c.Firstname, c.Lastname
             INTERSECT
             SELECT @firstname, @lastname)

逻辑是:对每一行,用两个值创建一个单行虚拟表,与两个变量相交,一定有结果。

对于<> 语义,将EXISTS 更改为NOT EXISTS,而不是更改为EXCEPT,我发现前者优化得更好。

All credit to Paul White 这个技巧。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-16
    • 2022-01-19
    • 1970-01-01
    • 2018-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多