Group String Concatenation:哪种方法(如果有的话)更有保证?

时间:2012-02-16 18:44:58

标签: sql sql-server-2008 tsql

Itzik Ben-Gan在他的书“InsideMicrosoft®SQLServer®2008:T-SQL”中解释了 Appoach A 如何工作,因为SQL Server的未记录行为在其中执行了来自SELECT的每个结果记录。

一位备受尊敬的同事和数据库专家建议方法B 保证有效。他的论点是基于COALESCECAST的'价值扩展'方法的递归性质。

实际上,我不知道“值扩展”指的是什么(除了它将一个值转换为另一个值的事实)或它如何应用于此问题?也许他误解了?是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;

4 个答案:

答案 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以某种方式更改了处理模型是不正确的。

即。一致的实现可以有效地将结果集中的每个潜在行(已评估FROMWHERE)移交给单独的线程,然后执行SELECT子句中所需的任何处理(之前)可能会重新合并结果,以便评估GROUP BYHAVINGORDER BY)。

在此类处理过程中没有管理变量访问权限的标准要求,因此每个主题可以“看到”@outputNULL''的相同初始值,具体取决于哪种形式您正在使用),执行自己的更新计算,并将结果值分配给@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是一种用替换值替换空值的方法。

编辑:

我应该补充一点,我也更喜欢第二个版本,因为你没有得到额外的分号,在输出结尾意味着会有更多的值。