将 IF EXISTS 移至 WHERE 子句
Posted
技术标签:
【中文标题】将 IF EXISTS 移至 WHERE 子句【英文标题】:Moving IF EXISTS to the WHERE clause 【发布时间】:2014-12-19 20:54:31 【问题描述】:在此示例查询中(针对设计不佳的供应商数据库):
DECLARE @OrderNo AS CHAR(8) = LEFT(@FullOrderNo,8)
IF EXISTS (SELECT 1 FROM Foo WHERE FullOrderNumber = @FullOrderNo)
SELECT Stuff
FROM Foo
WHERE X = 'Y'
AND FullOrderNumber = @FullOrderNo
ELSE
SELECT Stuff
FROM Foo
WHERE X = 'Y'
AND OrderNumber = @OrderNo
由于 SELECT 和 WHERE 子句的第一部分是相同的,有没有办法安全地组合查询同时确保首先检查 FullOrderNumber 匹配项?我看到有no guarantees for WHERE clause evaluation order。
【问题讨论】:
WHERE FullOrderNumber = @FullOrderNo OR OrderNumber = @OrderNo
@M.Ali:当有FullOrderNumber = @FullOrderNo
的记录时,这将返回OrderNumber = @OrderNo
不需要的记录
@M.Ali 如果在表中的任何地方都没有 FullOrderNumber 匹配项,我只想匹配 OrderNumber。
【参考方案1】:
你可以这样写:
SELECT Stuff
FROM Foo
WHERE X = 'Y' AND
(FullOrderNumber = @FullOrderNo OR
(NOT EXISTS (SELECT 1 FROM Foo WHERE FullOrderNumber = @FullOrderNo) and OrderNumber = @OrderNo) )
如果您只寻找一行,您可以使用order by
进行优先排序:
SELECT TOP (1) Stuff
FROM Foo
WHERE X = 'Y' AND
(FullOrderNumber = @FullOrderNo OR OrderNumber = @OrderNo)
ORDER BY (CASE WHEN FullOrderNumber = @FullOrderNo THEN 1 ELSE 2 END)
其实就算有重复,你也可以这样使用with ties
:
SELECT TOP (1) WITH TIES Stuff
FROM Foo
WHERE X = 'Y' AND
(FullOrderNumber = @FullOrderNo OR OrderNumber = @OrderNo)
ORDER BY (CASE WHEN FullOrderNumber = @FullOrderNo THEN 1 ELSE 2 END)
【讨论】:
这些例子可能会将两个语句重写为一个;但他们不保证:that FullOrderNumber matches are checked first
。如果 FullOrderNumber 上有索引,但 OrderNumber 上没有索引,则它可能会执行全表扫描(据推测 OP 试图通过此要求避免)。
@Gerrat 。 . .我将其解释为“首先返回完整的订单号”。但是,我不太确定 OP 是什么意思。
@GordonLinoff - 谢谢;澄清一下,我宁愿避免表扫描。如果原版表现更好,我会坚持下去。
@TrueWill 。 . . or
通常会导致表扫描。但是,数据的大小和第一个过滤器的选择性对性能有很大影响。
在答案中的第一个 SELECT 中,我认为您需要在表达式的 OR 部分周围加上括号。否则,它可以返回匹配 X <> 'Y'
.以上是关于将 IF EXISTS 移至 WHERE 子句的主要内容,如果未能解决你的问题,请参考以下文章
通过 FETCH NEXT 子句加速 WHERE EXISTS 子句
Linq to Entities 添加 Where 子句以在另一个表中查找 EXISTS