【问题标题】:Order of execution in SQL Server variable assignment using SELECT使用 SELECT 的 SQL Server 变量赋值中的执行顺序
【发布时间】:2013-01-30 19:00:51
【问题描述】:

举个例子:

declare @i int
select @i = 1, @i = 2
select @i

@i 会一直是 2 吗?

这是我能想到的最简单的例子,但我正在考虑使用它来交换变量中的值。我也相信这种分配方法(选择)不符合 ANSI(但很有用),但在这种情况下并不真正关心是否有可移植代码。

更新

感谢@MichaelFredrickson,我们有@MartinSmith 的answer 并在此引用MSDN。我现在正在努力理解本文档中第二句话的确切含义(强调):

如果单个 SELECT 语句中有多个赋值子句,SQL Server 不保证表达式的计算顺序。 请注意,只有在分配之间存在引用时才能看到效果。

然而,第一句话足以让我远离依赖行为。

【问题讨论】:

  • 不确定这是否在任何地方定义。我不会指望任何观察到的行为。
  • 这正是我所害怕的,所以可能不会为了节省一些位置而将其投入生产。
  • 剃掉一些 LOC 绝不是一个好的理由。让某些东西可靠地工作并使其可读胜过 LOC。
  • 别担心,完全同意。不过还是很有趣。

标签: sql sql-server tsql variable-assignment operator-precedence


【解决方案1】:

对于变量赋值,Martin Smith answers this question here引用MSDN

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

但是……

如果我们处理的是表格而不是变量,那就是另一回事了。

在这种情况下,Sql Server 使用 All-At-Once 操作,正如Itzik Ben-Gan in T-Sql Fundamentals 所讨论的那样。

这个概念表明,在同一逻辑阶段中的所有表达式都被评估为好像同一时间点......无论它们从左到右的位置如何。

所以在处理对应的UPDATE语句时:

DECLARE @Test TABLE (
    i INT,
    j INT
)

INSERT INTO @Test VALUES (0, 0)

UPDATE @Test
SET
    i = i + 10,
    j = i

SELECT 
    i, 
    j 
FROM 
    @Test

我们得到以下结果:

i           j
----------- -----------
10          0   

通过使用 All-At-Once 评估...在 Sql Server 中,您可以在没有中间变量/列的情况下交换表中的列值。

大多数 RBDMS 都以这种方式运行 as far as I know, but MySql is an exception


编辑:

请注意,只有在 任务。

我的理解是,如果您有如下 SELECT 声明:

SELECT
    @A = ColumnA,
    @B = ColumnB,
    @C = ColumnC
FROM MyTable

那么,分配的执行顺序无关紧要……无论如何,您都会得到相同的结果。但如果你有类似...

SELECT
    @A = ColumnA,
    @B = @A,
    @C = ColumnC
FROM MyTable

现在有一个分配之间的引用 (@B = @A),现在分配@A@B 的顺序很重要。

【讨论】:

  • +1,很好地找到了答案和几乎重复的问题。我曾辩论过在我的问题中承认列交换反例,但为简洁起见将其省略。现在,我应该投票结束我自己的问题吗?
  • @TimLehner 我花了很长时间才找到包含 Martin 答案的问题......而你刚刚发布的问题总是在我的谷歌搜索的顶部......我认为在非常至少,这个问题仍然可以作为指向另一个问题的指针,以及稍微扩展的讨论......
猜你喜欢
  • 2018-06-13
  • 2014-11-12
  • 1970-01-01
  • 2011-03-21
  • 1970-01-01
  • 1970-01-01
  • 2015-01-27
  • 1970-01-01
  • 2018-02-18
相关资源
最近更新 更多