SQL Server:此 SQL 语句如何工作
Posted
技术标签:
【中文标题】SQL Server:此 SQL 语句如何工作【英文标题】:SQL Server: How does this SQL statement work 【发布时间】:2016-03-26 00:34:37 【问题描述】:请解释此 SQL 语句如何选择所有 column1
值。
所以我有参数值 A、B 和 *
如果我通过@brand = '*'
,那么此语句将返回column1
中的所有值:
SELECT *
FROM TABLE
WHERE (column1 = @brand OR @brand = '*')
我在想,当@brand = '*'
时,它会将@brand
分配为TRUE
,所以column1
中的任何内容都将是true
,所以这就是它返回column1
中的所有值的原因
如果我通过A
,那么它只会返回A
值,如果B
然后B
值。
【问题讨论】:
【参考方案1】:你的假设是正确的。它根据最简单的路径依次评估您的WHERE
语句中的子句。
所以,因为有一个OR
,它首先评估@brand ='*'
子句;如果产生TRUE
,则满足WHERE
子句并且不再进行比较。
如果它产生FALSE
,那么它计算表达式中的另一个子句:column1 = @brand
。
但是,我应该注意,这不是在 SQL 中执行此操作的正确方法,因为 SQL Server 不保证短路,也不保证逻辑子句的执行顺序。它恰好在您的情况下以这种方式工作,但不能保证。您应该将WHERE
子句更改为如下所示:
((@brand = '*') OR (@brand <> '*' AND column1 = @brand))
【讨论】:
那么当它第一次将@brand = '*'
评估为TRUE
时,它如何知道将其应用于column1
? (因为没有进行进一步的比较)。我认为它只看到 @brand = '*'
而不是 column1 = @brand
@sojim2 这就是重点——它不适用于column1
。在OR
子句中,只有一侧需要为TRUE
- 因此两个子句运行的唯一方法是其中一个或两个语句是FALSE
。
举个例子,看看这个(非 SQL)代码:ideone.com/GmzhHU(我不能用 SQL 代码给你这样的例子,因为 SQL 不允许在表达式中产生副作用)。注意有一个基于OR
的if
语句(||
),并注意只有第一个函数是如何执行的。因为它产生true
,所以第二个不需要运行。程序已经知道如果第一个为真,则整个语句为真(1 或 0 = 1)。这称为 short-circuiting (虽然 SQL Server 并没有完全以相同的方式进行短路,但这超出了本问题的范围)。
@Ruslan,不,不能保证评估的顺序。见***.com/questions/484135/…。话虽如此,逻辑结果如前所述..
@DanGuzman 是的。他问为什么它以这种方式工作,而不是它是否是正确的方式。这就是我在评论中提到 的原因(尽管 SQL Server 并没有完全以同样的方式进行短路,但这超出了这个问题的范围)。但是,我同意我应该提到在 SQL 中执行此类操作的正确方法是((@brand = '*') OR (@brand <> ='*' AND column1 = @brand))
;将相应地编辑我的答案。【参考方案2】:
这条 SQL 语句是如何工作的?
你是在逻辑上提问吗?
SQL 使用三值逻辑。每个单独的谓词可以评估为真、假或未知。
您需要考虑示例中OR
的真值表,以了解如何组合谓词以获得整体结果。
在WHERE
子句的上下文中,整个谓词的计算结果必须为true
,才能在结果中返回行。
上面的真值表表明,只要知道其中一个谓词为真就足够了。因此,如果第一个评估为 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 = '*' );
执行计划显示如下
扫描整个表并在每一行上评估谓词。 SQL Server 可能会或可能不会按所示顺序评估条件,并且可能会或可能不会使用短路评估。这些信息不会向我们公开。
返回单行 - 第一行。
效率
上面查询的语义只是
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'
- 允许索引查找该特定值。
【讨论】:
以上是关于SQL Server:此 SQL 语句如何工作的主要内容,如果未能解决你的问题,请参考以下文章
有大神知道,sql server 中如何批量执行sql语句吗?