nvarchar连接/索引/nvarchar(max)的不可解释行为

28 浏览
0 Comments

nvarchar连接/索引/nvarchar(max)的不可解释行为

今天在SQL Server(包括2008R2和2012)中遇到了一个非常奇怪的问题。我正在尝试使用连接和select语句来构建一个字符串。

我已经找到了解决办法,但我真的很想了解这里发生了什么,为什么它没有给我预期的结果。有人可以解释一下吗?

http://sqlfiddle.com/#!6/7438a/1

根据请求,这里也有代码:

-- 基本表
create table bla (
    [id] int identity(1,1) primary key,
    [priority] int,
    [msg] nvarchar(max),
    [autofix] bit
)
-- 没有id列的主键表
create table bla2 (
    [id] int identity(1,1),
    [priority] int,
    [msg] nvarchar(max),
    [autofix] bit
)
-- nvarchar(1000)替换为max的表
create table bla3 (
    [id] int identity(1,1) primary key,
    [priority] int,
    [msg] nvarchar(1000),
    [autofix] bit
)
-- 将三个表填充相同的值
insert into bla ([priority], [msg], [autofix])
values (1, 'A', 0),
       (2, 'B', 0)
insert into bla2 ([priority], [msg], [autofix])
values (1, 'A', 0),
       (2, 'B', 0)
insert into bla3 ([priority], [msg], [autofix])
values (1, 'A', 0),
       (2, 'B', 0)
;
declare @a nvarchar(max) = ''
declare @b nvarchar(max) = ''
declare @c nvarchar(max) = ''
declare @d nvarchar(max) = ''
declare @e nvarchar(max) = ''
declare @f nvarchar(max) = ''
-- 我期望这个工作并生成'AB',但它没有
select @a = @a + [msg]
    from bla
    where   autofix = 0
    order by [priority] asc
-- 这个工作:转换为nvarchar(4000)
select @b = @b + convert(nvarchar(4000),[msg])
    from bla
    where   autofix = 0
    order by [priority] asc
-- 这个工作:没有WHERE子句
select @c = @c + [msg]
    from bla
    --where autofix = 0
    order by [priority] asc
-- 这个工作:没有ORDER BY子句
select @d = @d + [msg]
    from bla
    where   autofix = 0
    --order by [priority] asc
-- 这个工作:来自bla2,所以没有id上的主键
select @e = @e + [msg]
    from bla2
    where   autofix = 0
    order by [priority] asc
-- 这个工作:来自bla3,所以使用了msg的nvarchar(1000)而不是nvarchar(max)
select @f = @f + [msg]
    from bla3
    where   autofix = 0
    order by [priority] asc
select @a as a, @b as b, @c as c, @d as d, @e as e, @f as f

0
0 Comments

在SQL Server中,使用nvarchar类型的变量进行字符串拼接时,会出现一些无法解释的行为。有时它能正常工作,但有时却失败了,这取决于执行计划的选择。

问题的根源在于使用不受支持的方法对行进行字符串拼接。这种方法并没有得到官方文档的支持,因此无法保证其行为的一致性。这可能导致字符串拼接的结果在不同的执行计划下产生不同的结果。

为了解决这个问题,可以使用以下几种方法来确保字符串拼接的正确性。

对于SQL Server 2017及以上版本,可以使用STRING_AGG函数来实现字符串拼接:

SELECT  = STRING_AGG([msg], '') WITHIN GROUP (ORDER BY [priority] ASC)
FROM bla
WHERE autofix = 0

对于SQL Server 2005及以上版本,可以使用FOR XML PATH函数来实现字符串拼接:

SELECT  = (SELECT [msg] + ''
           FROM   bla
           WHERE  autofix = 0
           ORDER  BY [priority] ASC
           FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)')

这些方法都是可靠的,可以保证字符串拼接的正确性。

关于这个问题,微软的官方回复是:这种字符串拼接的行为是未定义的,不能保证其正确性。在SQL Server的查询计划中,对于变量的赋值操作(比如字符串拼接)并不保证每一行都会执行一次。查询优化器会尽量减少这种操作的执行次数,这就导致了一些意外的结果。

因此,在进行字符串拼接时,应该使用官方支持的方法,如使用游标、FOR XML查询或CLR聚合函数等。这些方法都能够保证字符串拼接的正确性。

总之,对于nvarchar类型的字符串拼接,在SQL Server中存在一些无法解释的行为。为了避免出现问题,应该使用官方支持的方法来实现字符串拼接,并避免使用不受支持的方法。

0
0 Comments

nvarchar concatenation / index / nvarchar(max) inexplicable behavior 的问题是关于在字符串连接时出现的不确定行为。根据一篇Stack Overflow的帖子,官方对于类似问题的解释是“对于聚合连接查询的正确行为是未定义的”。这个问题的出现可能是因为SQL Server没有对字符串连接的行为进行明确的定义,所以在使用这种方法时出现了不确定的结果。

虽然该问题在SQL Server 2000和7.0中存在,但官方并没有对此进行修复。这是因为官方从未保证过字符串连接的行为,所以不能依赖于它。如果想要替代的方法,可以参考一篇名为“Concatenating Row Values in Transact-SQL”的文章。

nvarchar字符串的连接在SQL Server中可能会出现不确定的行为,并且官方并没有对此进行明确的定义。要解决这个问题,可以考虑使用替代的方法来进行字符串连接。

0