WHERE 子句使用可能为 NULL 的值

WHERE clause using values that could be NULL

我需要做这样的事情:

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

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

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

如果这些变量之一是 NULL,如果数据库中的对应值也是 NULL,我想 return 匹配。但是,当然,SQL 服务器使用 IS 来比较 NULL。如果上述示例中任一值为 NULL,则不认为是匹配项。

有什么办法可以做到吗?

只需使用 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);

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

编译器将 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)

逻辑是:对于每一行,用两个值创建一个单行虚拟table,将它与两个变量相交,并且必须有一个结果。

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

All credit to Paul White 这个技巧。