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

时间:2018-03-03 12:59:56

标签: sql sql-server tsql

我想将参数@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)

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

有人可以解释一下吗?

3 个答案:

答案 0 :(得分: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的结果实际上是unknown - 并且任何查询使用null = null因为它的where子句将不会返回任何结果,除非ANSI_NULLS设置为OFF(由于它已被弃用,您实际上不应该这样做。)< / p>

索引使用

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

<强>结论

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

答案 1 :(得分:1)

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

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

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

答案 2 :(得分: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;