【问题标题】:SQL assign variable with subquerySQL 使用子查询分配变量
【发布时间】:2017-07-28 07:14:04
【问题描述】:

我对以下 2 个 SQL 有疑问:

declare @i1 bit, @b1 bit
declare @i2 bit, @b2 bit
declare @t table (Seq int)
insert into @t values (1)

-- verify data
select case when (select count(1) from @t n2 where 1 = 2) > 0 then 1 else 0 end
-- result 0

select @i1 = 1, @b1 = case when @i1 = 1 or ((select count(1) from @t n2 where 1 = 2) > 0) then 1 else 0 end from @t n where n.Seq = 1
select @i1, @b1
-- result 1, 0

select @i2 = 1, @b2 = case when @i2 = 1 or (0 > 0) then 1 else 0 end from @t n where n.Seq = 1
select @i2, @b2
-- result 1, 1

SQL Fiddle Here

在执行之前,我认为case部分应该是null = 1 or (0 > 0),它会返回0

但是现在,我想知道为什么第二个 SQL 会返回 1

【问题讨论】:

  • 变量的顺序。检查demo。当您拥有select @b2 = case when @i2 = 1 or (0 > 0) then 1 else 0 end ,@i2 = 1 时,您将获得 1,0
  • 我更感兴趣的是这两者的区别:select @i1 = 1, @b1 = (case when @i1 = 1 or ((select count(1) from @t n2 where 1 = 2) > 0) then 1 else 0 end) from @t n where n.Seq = 1 select @i1, @b1 -- result 1, 0 select @i1 = 1, @b1 = (case when @i1 = 1 then 1 else 0 end) from @t n where n.Seq = 1 select @i1, @b1
  • The order of evaluation isn’t defined,所以我猜 SQL Server 只是通过添加子查询选择了一个不同的。
  • Dirty Secrets of the CASE Expression - CASE will not always short circuit 部分 + 到 ms 连接的链接。

标签: sql sql-server tsql


【解决方案1】:

我会将这个作为答案发布,因为它是来自Training Kit (70-461) 的相当大的文本:

WHERE propertytype = 'INT' AND CAST(propertyval AS INT) > 10

有些人假设除非优先规则另有规定,否则谓词 将从左到右进行评估,并且短路将 尽可能进行。换句话说,如果第一个谓词 propertytype = 'INT' 计算结果为 false,SQL Server 不会计算 第二个谓词 CAST(propertyval AS INT) > 10 因为结果是 已经知道了。基于这个假设,期望是 查询应该永远不会失败尝试转换不是 敞篷车。

然而,现实是不同的。 SQL Server 可以 内部支持短路概念;然而,由于 all-at-once 概念在语言中,不一定会 按从左到右的顺序计算表达式。它可以决定, 基于与成本相关的原因,从第二个表达式开始, 然后如果第二个表达式的计算结果为真,则计算 第一个表达式也是如此。这意味着如果在 属性类型不同于“INT”的表,并且在这些行中 propertyval 不能转换为 INT,查询可能会失败,因为 转换错误。

【讨论】:

  • 其实我不确定这是否回答了你的问题,但看起来它与这个概念有关。
  • 是的,这似乎是答案的一部分,由于“与成本相关的原因”,它首先评估when 语句(带有子查询),然后是case,然后分配@i在最新阶段。在 SQL 的 order 中,由于所有“part”具有相同的“cost”,所以它从左到右评估
【解决方案2】:

只是为了扩展@Giorgi 的回答:

看到这个执行计划: 由于首先计算 @i2 (@i2=1),所以 case when @i2 = 1 or anything 返回 1。

另请参阅此 msdn 条目:https://msdn.microsoft.com/en-us/library/ms187953.aspx注意 部分

如果单个 SELECT 语句中有多个赋值子句, SQL Server 不保证计算的顺序 表达式。请注意,效果只有在有 作业之间的引用。

都和内部优化有关。

【讨论】:

  • 那么为什么@i1 不是这样呢?
  • 我已经扩展了我的答案。
  • 基本上,这个Caution句子是重点和问题的答案。
  • 感谢您提供的信息,但似乎不是我的情况。通过执行计划(在这种情况下文本会更好),它表明将首先执行WHERE,由于Giorgi Nakeuri的回答提到的与成本相关的原因。
【解决方案3】:

只是为了扩展两个答案。

来自Dirty Secrets of the CASE Expression

CASE 不会总是短路

官方文档暗示整个表达式会短路,这意味着它将从左到右评估表达式,并在匹配时停止评估:

The CASE statement  evaluates its conditions sequentially and stops with the
first condition whose condition is satisfied.

和 MS Connect:

CASE Transact-SQL

CASE 语句按顺序评估其条件,并在满足条件的第一个条件处停止。在某些情况下,在 CASE 语句接收表达式结果作为其输入之前计算表达式。 评估这些表达式时可能会出错。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-28
    • 1970-01-01
    相关资源
    最近更新 更多