将 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

Oracle where exists 子句不适用于 SQL Plus

使用 where exists 子句更新多个值

如何将 if 条件放在 where 子句中

EXISTS 和 IN 的区别