使用IS NULL或Coalesce将参数传递给where子句

问题描述 投票:-3回答:3

我想将参数@CompanyID传递给where子句来过滤结果。但有时这个值可能是null所以我想要返回所有记录。我找到了两种方法,但不确定哪种方法最安全。

版本1

SELECT ProductName, CompanyID 
FROM Products 
WHERE (@CompanyID IS NULL OR CompanyID = @CompanyID)

版本2

SELECT ProductName, CompanyID 
FROM Products 
WHERE CompanyID = COALESCE(@CompanyID, CompanyID)

我发现第一个版本是最快的,但我也发现在其他表中使用类似的方法,我得到了不同的结果集。我不太明白两者之间的差异。

有人可以解释一下吗?

sql sql-server tsql
3个回答
2
投票

好吧,两个查询都处理相同的两个场景 - 在一个场景中,@CompanyID包含一个值, 在第二个@CompanyID包含NULL

对于这两个查询,第一个场景将返回相同的结果集 - 因为如果@CompanyId包含一个值,则两者都将返回companyId = @CompanyId所有的行,但是第一个查询可能会更快地返回它(在我的答案结束时更多)。

但是,第二种情况是查询开始表现不同。

首先,这就是为什么你得到不同的结果集:

结果集的差异

版本1

WHERE (@CompanyID IS NULL OR CompanyID = @CompanyID)

@CompanyID为null时,where子句不会过滤掉任何行,并且将返回表中的所有记录。

版本2

WHERE CompanyID = COALESCE(@CompanyID, CompanyID)

@CompanyID为null时,where子句将过滤掉CompanyID为null的所有行,因为null = null的结果实际上是unknown - 并且任何使用null = null的查询,因为它的where子句将不返回任何结果,除非ANSI_NULLS设置为OFF(其中你不应该这样做,因为它被弃用了)。

索引用法

您可能会从第一个版本获得更快的结果,因为在where子句中使用列上的任何函数将阻止SQL Server使用您在此列上可能具有的任何索引。您可以在MSSql Tips中的this article上阅读更多相关信息。

结论

版本1优于版本2.即使您不想返回companyId为null的记录,写入WHERE (@CompanyID IS NULL OR CompanyID = @CompanyID) AND CompanyID IS NOT NULL仍然比使用第二个版本更好。


1
投票

值得注意的是,使用语法([Column] = @Value OR [Column] IS NULL)比使用ISNULL([Column],@Value) = @Value(或使用COALESCE)更好。

这是因为使用该函数会导致查询变为un-SARGable;因此不会使用索引。第一个表达式是SARGable,因此表现更好。

只是添加这个,因为OP声明“我发现第一个版本是最快的”,并想详细阐述原因(即使目前声明不完整,我猜这更多是由于用户错误和无知)。


0
投票

第二个版本不正确SQL(对于SQL Server)。它需要一个操作员。想必:

SELECT ProductName, CompanyID 
FROM Products 
WHERE COALESCE(@CompanyID, CompanyID) = CompanyID;

第一个版本正如所写。如果你有CompanyID的索引,你可能会发现这更快:

SELECT * 
FROM Products 
WHERE CompanyID = @CompanyID
UNION ALL
SELECT * 
FROM Products 
WHERE @CompanyID IS NULL;
© www.soinside.com 2019 - 2024. All rights reserved.