我在条件中有三个 OR 。
问题是第一个条件变为现实,但它也会检查其他条件并评估最后一个条件。
declare @SearchByParam varchar(20)
set @SearchByParam= 3
Select b.BookingID, ISNULL(Convert(varchar(11),b.AppointmentDate,106),'') as AppointmentDate, isnull(ts.FromTo,'N/A') FromTo, c.CustomerName, c.VehicleRegNo, ISNULL(b.HasCustomerArrived,0) as HasCustomerArrived, ISNULL(b.IsOrderCancelled,0) as IsOrderCancelled
from Bookings b
inner join Customers c
on c.CustomerID= b.fk_CustomerID
left join TimeSlots ts
ON ts.TimeSlotID= b.fk_TimeSlotID
where
b.BookingID= TRY_CONVERT(int, @SearchByParam)
OR
c.CustomerName like '%'+ @SearchByParam +'%'
OR
c.VehicleRegNo like '%'+ @SearchByParam +'%'
请参阅b.BookingID= TRY_CONVERT(int, @SearchByParam)
获得3,但它也会评估其他条件。
为什么?它应该在第一个停止。
答案 0 :(得分:2)
你假设如果它的代数可以短路,那么它应该短路。但这会降低并行性的好处,特别是在使用多行而不是单个标量表达式(例如在C中)时。
为了最大化并行操作,可以生成执行计划,使得短路不会带来任何好处。这就是SQL为declarative
而不是imperative
的原因;你声明一个问题,然后SQL Server创建计划来解决这个问题。 (命令式语言执行您提供的解决方案。) - 在SQL
中,您无法通过更改表达式的顺序来控制已执行操作的顺序。
尝试 强制 的一个选项是将所有三个表达式折叠到单个CASE
表达式中,因为这是一个线性标量操作
1 = CASE WHEN b.BookingID = TRY_CONVERT(int, @SearchByParam) THEN 1
WHEN c.CustomerName like '%'+ @SearchByParam +'%' THEN 1
WHEN c.VehicleRegNo like '%'+ @SearchByParam +'%' THEN 1 END
然而,这极大地限制了规划人员的选择,您可能会发现性能下降。
<强> 编辑: 强>
自从我开始编写这个答案以来,已经阅读了添加的评论,我认为您已经误解了SQL。这不是短路问题。在SQL中,WHERE
子句应用于所有其他行的每个输入行 。
例如,以下内容返回myfield
为'x'
或'y'
的所有行。 不 会返回'x'
所有行,并且只有在'y'
没有出现时才会搜索'x'
找到了......
WHERE myfield = 'x' OR myfield = 'y'
-- Which is the same as...
WHERE myfield IN ( 'x', 'y' )
在您的情况下,您似乎正在尝试实施动态搜索条件。其中有 许多不良方式 ,并且只有 一些好方法 才能做到这一点。
过于简单&#34;没有好处&#34;方式就是这个......
DECLARE @SearchByParam VARCHAR(20) = '3',
@SearchByType INT = 1
SELECT
<blah>
WHERE
(@SearchByType = 1 AND b.BookingID= TRY_CONVERT(int, @SearchByParam))
OR (@SearchByTYpe = 2 AND c.CustomerName like '%'+ @SearchByParam +'%' )
OR (@SearchByType = 3 AND c.VehicleRegNo like '%'+ @SearchByParam +'%' )
它&#34;不好&#34;因为如果您确实希望按BookingID
进行搜索,则会破坏优化程序围绕任何索引构建查询的能力。
对于三个查询,您实际上会更好,每个查询都根据不同的搜索条件进行定制。或者可能是动态SQL,在那里向查询字符串添加必要的WHERE
子句,然后执行该字符串。
对于小数据量,上面的示例可能会对您有所帮助。对于较大的数据量,要么使用专用于每个用例的多个查询,要么阅读此(非常深入,但非常有用)文章:http://www.sommarskog.se/dyn-search.html
答案 1 :(得分:0)
您可以将where子句重写为:
where
b.BookingID= TRY_CONVERT(int, @SearchByParam)
OR
(
c.CustomerName like '%'+ @SearchByParam +'%' and b.BookingID != TRY_CONVERT(int, @SearchByParam)
OR
c.VehicleRegNo like '%'+ @SearchByParam +'%' and b.BookingID != TRY_CONVERT(int, @SearchByParam)
)
答案 2 :(得分:0)
这个问题的最佳解释是我在70-761考试准备书中找到的那个。 SQL是一种声明性语言。这意味着您描述了您想要获得的内容,但是如何将其用于数据库引擎。因为它你不能假设WHERE clasue中的所有状态将从左到右处理。引擎可以选择以您在原始语句中放入的不同顺序来预测谓词。
答案 3 :(得分:0)
从注释和可能的重复答案中可以清楚地看到,编程语言中的短路布尔逻辑在sql server中并不保证,因此您必须使用其他选项,如此。
sql server仍然可以检查所有条件,但它的确会产生与逻辑相同的方式,因此它实际上模拟了短路布尔逻辑,但也确保了sql server无法创建查询计划遗漏了“短路”
declare @SearchByParam varchar(20)
set @SearchByParam= 3
Select b.BookingID,
ISNULL(Convert(varchar(11),b.AppointmentDate,106),'') as AppointmentDate,
isnull(ts.FromTo,'N/A') FromTo,
c.CustomerName,
c.VehicleRegNo,
ISNULL(b.HasCustomerArrived,0) as HasCustomerArrived,
ISNULL(b.IsOrderCancelled,0) as IsOrderCancelled
from Bookings b
inner join Customers c
on c.CustomerID = b.fk_CustomerID
left join TimeSlots ts
ON ts.TimeSlotID = b.fk_TimeSlotID
where b.BookingID = TRY_CONVERT(int, @SearchByParam)
OR (b.BookingID <> TRY_CONVERT(int, @SearchByParam)
and
c.CustomerName like '%'+ @SearchByParam +'%'
)
OR (b.BookingID <> TRY_CONVERT(int, @SearchByParam)
and
c.VehicleRegNo like '%'+ @SearchByParam +'%'
)