8

给定以下示例:

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

永远@i是2?

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

更新

感谢@MichaelFredrickson,我们有@MartinSmith 的回答和对MSDN的参考。我现在正在为本文档中第二句话的确切含义而苦苦挣扎(强调):

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

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

4

1 回答 1

6

对于变量赋值, Martin Smith 在这里参考MSDN回答了这个问题

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

但...

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

在这种情况下,Sql Server 使用All-At-Once操作,正如Itzik Ben-Gan 在 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   

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

据我所知,大多数 RBDMS 都以这种方式运行,但 MySql 是一个例外。


编辑:

请注意,只有在分配之间存在引用时,效果才可见。

我理解这意味着如果您有SELECT如下声明:

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

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

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

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

于 2013-02-14T21:41:40.160 回答