首先让我说我完全清楚sql server没有短路评估。如果因为执行计划而认为合适,那就可以了,但最好不要猜测。
我想知道是否可以在任何特定情况下强制使用null - 例如在此查询中动态加载所有客户
declare @customerId int set @customerId = null select * from customer where ( (@customerId Is Null) Or CustomerId=@customerId)
CustomerId是PK(int),不可为空
问题:在这种情况下,是否有人知道引擎是否总是选择左侧,或者我们是否确实最终检查每行的右侧是否有CustomerId = null。 我猜这不能保证工作,因为右侧可能“选择性较差”但我很好奇,如果sql服务器看到null并且知道在每种情况下这样使用左侧因为null声明。 我认为这最好是作为下面的案例stmt完成(如果你可以更好地查询下面的请求!)但我只是好奇这个案例用于学习目的,如果有人知道这里一致的内部行为。它适用于我的所有情况,但它也是一个主键,不可空,所以这可能是这总是有效的原因。如果它是一个可以为空的类型,那么右手边的选择性可能低于左边,我们现在处理的是另一种情况。
我在两个查询中的执行计划似乎都是一样的。
无论如何 - 这是一种更好的写作方式(如果可以,请加强)
declare @customerId int set @customerId = null select * from Customer where case when @customerId is null then 1 end = 1 or case when @customerId is not null then @customerId else -1 end = CustomerId
这里的想法是为动态sql提供变通方法 - 所以我只是想确保我知道所有情况。
谢谢!
答案 0 :(得分:3)
这里的主要问题不是短路。
当SQL Server编译批处理
时declare @customerId int
set @customerId = null
select * from customer where ( (@customerId Is Null) Or CustomerId=@customerId)
它没有做任何类型的“变量嗅探”,它考虑到前面的赋值语句,它只是将@customerId
的值视为未知。
如果您使用的是某些版本的SQL Server 2008,则可以使用OPTION(RECOMPILE)
让它在分配变量后重新编译该语句。
答案 1 :(得分:3)
你可以试试这个:
...WHERE CustomerId = COALESCE(@customerId, CustomerId)
或者,如果您愿意,可以使用“扩展”版本的COALESCE:
...WHERE CustomerId = CASE
WHEN @customerId IS NULL THEN CustomerId
ELSE @customerId
END