Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server nvarchar串联/索引/nvarchar(最大值)无法解释的行为_Sql Server_Sql Server 2012_String Concatenation_Nvarchar - Fatal编程技术网

Sql server nvarchar串联/索引/nvarchar(最大值)无法解释的行为

Sql server nvarchar串联/索引/nvarchar(最大值)无法解释的行为,sql-server,sql-server-2012,string-concatenation,nvarchar,Sql Server,Sql Server 2012,String Concatenation,Nvarchar,我今天在SQL Server中遇到了一个非常奇怪的问题(2008R2和2012)。我正在尝试使用连接和select语句来构建一个字符串 我已经找到了解决办法,但我真的很想了解这里发生了什么,为什么它没有给我预期的结果。有人能给我解释一下吗 根据要求,也可在此处输入代码: -- base table create table bla ( [id] int identity(1,1) primary key, [priority] int, [msg] nvarchar(m

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

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

根据要求,也可在此处输入代码:

-- base table
create table bla (
    [id] int identity(1,1) primary key,
    [priority] int,
    [msg] nvarchar(max),
    [autofix] bit
)

-- table without primary key on id column
create table bla2 (
    [id] int identity(1,1),
    [priority] int,
    [msg] nvarchar(max),
    [autofix] bit
)

-- table with nvarchar(1000) instead of max
create table bla3 (
    [id] int identity(1,1) primary key,
    [priority] int,
    [msg] nvarchar(1000),
    [autofix] bit
)

-- fill the three tables with the same values
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) = ''

-- I expect this to work and generate 'AB', but it doesn't
select @a = @a + [msg]
    from bla
    where   autofix = 0
    order by [priority] asc

-- this DOES work: convert nvarchar(4000)
select @b = @b + convert(nvarchar(4000),[msg])
    from bla
    where   autofix = 0
    order by [priority] asc

-- this DOES work: without WHERE clause
select @c = @c + [msg]
    from bla
    --where autofix = 0
    order by [priority] asc

-- this DOES work: without the order by
select @d = @d + [msg]
    from bla
    where   autofix = 0
    --order by [priority] asc

-- this DOES work: from bla2, so without the primary key on id
select @e = @e + [msg]
    from bla2
    where   autofix = 0
    order by [priority] asc

-- this DOES work: from bla3, so with msg nvarchar(1000) instead of 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

看起来有点像这篇文章:

结论如下: 这种字符串连接方法通常是有效的,但不能保证。 类似的问题是“聚合连接查询的正确行为未定义。”

VanDerNorth已经链接的内容中确实包含该行

聚合连接查询的正确行为是 未定义

但随后,通过提供一个似乎确实表明确定性行为是可能的解决办法,使水变得有点浑浊

为了达到预期的效果,从一个总体上来说 连接查询,将任何Transact-SQL函数或表达式应用于 选择列表中的列,而不是ORDER BY子句中的列

有问题的查询没有将任何表达式应用于
ORDER BY
子句中的列

2005年的文章没有说明

出于向后兼容性的原因,SQL Server提供了对 选择@p=@p+1类型的赋值。。。按最上面的顺序订购 范围

在串联按预期工作的计划中,带有表达式
[Expr1003]=标量运算符([@x]+[Expr1004])
的计算标量显示在排序上方

在无法工作的计划中,计算标量显示在排序下面。如从2006年开始解释的,当表达式
@x=@x+[msg]
出现在排序的下面时,它会对每一行进行求值,但所有求值最终都使用预赋值值
@x
。从2006年开始,微软的回应谈到“修复”这个问题

Microsoft对此问题的所有后续连接项目(还有许多)的回复表明,这根本无法保证

我们不保证连接的正确性 查询(如在数据库中使用变量赋值和数据检索) 具体顺序)。SQL Server 2008中的查询输出可能会更改 根据计划选择、表格中的数据等,您不应该 即使语法允许您 编写一个SELECT语句,将有序行检索与 变量赋值

你看到的行为是故意的。使用赋值操作 (本例中的连接)在带有ORDERBY子句的查询中 未定义的行为。这可能会随着版本的不同而变化,甚至会发生变化 由于查询计划中的更改,在特定服务器版本中。 即使存在变通方法,也不能依赖此行为。看见 有关详细信息,请参阅以下知识库文章:
唯一的保证 机制如下:

  • 使用游标按特定顺序循环遍历行并连接值
  • 用于带有ORDER BY的xml查询,以生成连接的值
  • 使用CLR聚合(这不适用于ORDER BY子句)
  • 你看到的行为实际上是故意的。这是因为 SQL是一种集合操作语言。“选择”对话框中的所有表达式 列表(也包括作业)不保证 对每个输出行执行一次。实际上,SQL查询 优化器努力尽可能少地执行它们。这 将在计算 变量基于表中的某些数据,但当 是否赋值取决于同一变量的上一个值 结果可能出乎意料。如果查询优化器移动 表达式在查询树中的其他位置,它可能会 计算次数较少(或仅一次,如您的示例中所示)。这 这就是为什么我们不建议使用“迭代”类型分配来 计算聚合值。我们发现基于XML的变通方法。。。通常情况下,这对工作很有帮助 顾客

    即使没有ORDER BY,我们也不保证@var=@var+ 将为任何语句生成连接的值 这会影响多行。表达式的右侧可以 在查询执行过程中计算一次或多次 正如我所说的,这种行为取决于计划

    SELECT语句的变量赋值是一种专有语法 (仅限T-SQL)行为未定义或与计划相关,如果 生成多行。如果需要进行字符串连接 然后使用SQLCLR聚合或基于XML查询的连接或 其他关系方法


    这是一个很好的问题,但是你能在问题中包含一些重现问题所需的代码吗?SQLFiddle非常有用,但是代码不应该只存在于那里。你的确切意思是什么?这是SQL中的问题,而不是其他地方的问题。。对吗?我是说你在SQLfiddle上的复制,但它在问题的代码块中。啊。当然将其添加到问题中。:)嗯,谢谢。但这并不能真正让我满意,“未定义的行为”。其次,您提到的知识库文章适用于SQLServer2000和7.0;巴特拉霍芬:现在还不应该纠正吗?没有什么可以纠正的,因为这种行为从来没有得到过保证,所以你不应该依赖它。有关其他方法,请参阅。非常好的信息/很好了解。遗憾的是,连接链接现在都死了。我试着在新的但可怕的UserVoice系统上找到其中一些,但是找不到。然而,我确实找到了两个新的链接(我用这个答案的链接对它们进行了评论):一方面如此