我想将参数@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)
我发现第一个版本是最快的,但我也发现在其他表中使用类似的方法,我得到了不同的结果集。我不太明白两者之间的差异。
有人可以解释一下吗?
答案 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;