SQL Server:此SQL语句如何工作

时间:2016-03-26 00:34:38

标签: sql-server

请解释此SQL语句如何选择所有column1值。

所以我有参数值A,B和*

如果我传递@brand = '*',则此语句将返回column1中的所有值:

SELECT * 
FROM TABLE 
WHERE (column1 = @brand OR @brand = '*')

我在考虑,@brand = '*'然后它将@brand指定为TRUE,因此column1中的任何内容都是true,这就是为什么它返回column1

中的所有值

如果我通过A,则只会返回A个值,如果B,则B值。

2 个答案:

答案 0 :(得分:3)

你的假设是正确的。它依次根据最简单的路径评估WHERE语句中的子句。

所以,因为有OR,它首先评估@brand ='*'子句;如果它产生TRUE,则WHERE子句得到满足,并且不再进行进一步的比较。

如果它产生FALSE,则它会计算表达式中的另一个子句:column1 = @brand

但是,我应该注意,这不是在SQL中执行此操作的正确方法,因为SQL Server不保证短路也不保证逻辑子句的执行顺序。它碰巧在你的情况下以这种方式工作,但不能保证。您应该将WHERE子句更改为如下所示:

((@brand = '*') OR (@brand <> '*' AND column1 = @brand))

答案 1 :(得分:1)

  

此SQL语句如何工作?

你在逻辑上问吗?

SQL使用三值逻辑。每个单独的谓词都可以评估为真,假或未知。

您需要在示例中考虑OR的真值表,以了解如何组合谓词以获得整体结果。

enter image description here

WHERE子句的上下文中,对于要在结果中返回的行,整个谓词必须求值为true

上面的真值表表明,只要知道其中一个谓词是真的就足够了。因此,如果第一个评估为真,则无需评估第二个。这被称为短路评估。

SQL Server不保证评估顺序或它将使用短路评估。

示例

DECLARE @Table TABLE (
  column1 VARCHAR(50) PRIMARY KEY);

INSERT INTO @Table
VALUES     ('brand1'),
            ('brand2'),
            ('brand3')

DECLARE @brand VARCHAR(50) = 'brand1'

SELECT *
FROM   @Table
WHERE  ( column1 = @brand
          OR @brand = '*' );

执行计划显示以下内容

enter image description here

扫描整个表并在每行上评估谓词。 SQL Server可能会也可能不会按所示顺序评估条件,可能会也可能不会使用短路评估。此信息不会向我们公开。

返回一行 - 第一行。

enter image description here

<强>效率

上面查询的语义只是

SELECT * 
FROM @Table 
WHERE column1= 'brand1'

应该可以通过对支持主键的索引进行简单查找来评估 - 而不是扫描整个表。

从SQL Server 2008开始,您可以使用以下

DECLARE @brand VARCHAR(50) = 'brand1'

SELECT * 
FROM @Table 
WHERE (column1 = @brand OR @brand = '*')
OPTION (RECOMPILE)

这会在执行它之前重新编译语句,并且不会缓存执行计划。这意味着该计划可以考虑@brand通过的具体值。

现在@brand = '*'的比较在编译时完成,并确定为假,谓词简化为column1 = 'brand1' - 允许索引寻找该特定值。

enter image description here