Itzik Ben-Gan在他的书“InsideMicrosoft®SQLServer®2008:T-SQL”中解释了 Appoach A 如何工作,因为SQL Server的未记录行为在其中执行了来自SELECT
的每个结果记录。
一位备受尊敬的同事和数据库专家建议方法B 保证有效。他的论点是基于COALESCE
与CAST
的'价值扩展'方法的递归性质。
实际上,我不知道“值扩展”指的是什么(除了它将一个值转换为另一个值的事实)或它如何应用于此问题?也许他误解了?是COALESCE
在某种意义上是递归的,但据我所知,它是无关紧要的,并且由于多重赋值的无证行为而产生了期望的结果。
他是对的吗?请不要“使用FOR XML PATH
代替”答案!
接近A
DECLARE @output VARCHAR(100);
SET @output = '';
SELECT @output = @output + CAST(COL_VCHAR AS VARCHAR(10)) + ';'
FROM someTable;
方法B
DECLARE @output VARCHAR(100);
SELECT @output = COALESCE(@output + ', ', '') + COL_VCHAR
from someTable;
答案 0 :(得分:4)
我认为他们都是因为相同的潜在(和未记录)行为而工作。我相当有信心,如果你认为Itzik已证明方法A 失败,那么方法B 也将以同样的方式失败,出于同样的原因,尽管你的同事声称。我不知道如何
DECLARE @output VARCHAR(100);
SELECT @output = COALESCE(@output + ', ', '') + COL_VCHAR
与...不同:
DECLARE @output VARCHAR(100) = '';
SELECT @output = @output + ', ' + COL_VCHAR
-- or SELECT @output += ',' + COL_VCHAR
那么COALESCE
神奇地引入了什么呢? SQL Server不会因为您对输出AFAIK所做的事情而改变其计划。
我一直使用它们来生成动态SQL,并且不记得曾经看到它们失败,我意识到这不是你的问题。不幸的是,除非你知道任何一种方法都失败了,否则没有办法证明它。
几个月前我写了一篇关于字符串连接的博客文章。这与你的问题并不完全相关,但Rob Farley发表评论可能被认为是COALESCE
方法的另一个缺点:
https://sqlblog.org/2011/03/08/t-sql-tuesday-16-this-is-not-the-aggregate-youre-looking-for
答案 1 :(得分:2)
由于符合标准的SQL实现可以同时评估所有输出行,因此保证都不能正常工作。今天它们发生工作,是当前SQL Server实现的工件。
您的同事声称COALESCE
以某种方式更改了处理模型是不正确的。
即。一致的实现可以有效地将结果集中的每个潜在行(已评估FROM
和WHERE
)移交给单独的线程,然后执行SELECT
子句中所需的任何处理(之前)可能会重新合并结果,以便评估GROUP BY
,HAVING
和ORDER BY
)。
在此类处理过程中没有管理变量访问权限的标准要求,因此每个主题可以“看到”@output
(NULL
或''
的相同初始值,具体取决于哪种形式您正在使用),执行自己的更新计算,并将结果值分配给@output
- @output
的最终值可能是任何单个行结果 - 或其他任何相关内容。< / p>
答案 2 :(得分:0)
在您的示例中,有一种方法可以获得不同的结果,即如果将NULL值引入数据集。 e.g:
set nocount on
declare @test table (value int)
insert into @test values (10)
insert into @test values (20)
insert into @test values (null)
insert into @test values (40)
insert into @test values (50)
DECLARE @output VARCHAR(max);
-- Approach A
SET @output = '';
SELECT @output = @output + CAST(value AS VARCHAR(10)) + ';'
FROM @test
print 'Result from A:'
print isnull(@output, '{null}')
-- Approach B
set @output = ''
SELECT @output = COALESCE(@output + ', ', '') + cast(value as varchar(10))
from @test
print 'Result from B:'
print isnull(@output, '{null}')
set nocount off
方法A将返回null,而方法B将返回40, 50
答案 3 :(得分:0)
它们的工作方式不同,第一个示例在输出变量的末尾添加了一个额外的字符,是的,它们因为相同的行为而起作用。
如果您的列也是数字或日期,则第一个示例将起作用。但是,它只会占据列中任何值的前10个字符。第二个例子不会切断列。
COALESCE绝对没有递归特性。 COALESCE是一种用替换值替换空值的方法。
编辑:
我应该补充一点,我也更喜欢第二个版本,因为你没有得到额外的分号,在输出结尾意味着会有更多的值。