意外的字符串连接结果

时间:2013-04-04 12:10:58

标签: sql-server sql-server-2008 tsql

想象一下以下架构:

create table tempdb..t1 (id int, name sysname); 
create table tempdb..t2 (id int, name sysname); 
create index IX1 on tempdb..t1 (id); 
create index IX2 on tempdb..t2 (id);

现在我正在尝试编写索引定义脚本:

declare @stmt nvarchar(max) = '';
select @stmt += 'create index ' + ix.name + ' on ' + t.name 
    + isnull(' where ' + ix.filter_definition, '') + char(13)
    from tempdb.sys.tables t
    join tempdb.sys.indexes ix on t.object_id = ix.object_id
    where ix.type > 0 and t.name in ('t1','t2')
    order by ix.name;
print @stmt;

我希望得到两个索引定义:

create index IX1 on t1
create index IX2 on t2

但只获得第二名。如果我删除order byisnull部分,或添加top语句,我会得到两个定义。

我错过了一些明显的东西吗?

2 个答案:

答案 0 :(得分:0)

当您使用select将值放入标量变量时,只会在变量中放入一行。它不会将您的两行(或结果集大小)聚合成一行。

想象一下,你有一个变量是一个整数,你尝试为它分配700个不同的值,这是行不通的。尝试将两个字符串分配给同一个变量也是一样的。相反,只会使用其中一个值。

declare @i int;

SELECT @i = t.value
FROM myTable AS t
WHERE t.value between 1 and 700

SELECT @i

创建伪字符串连接聚合函数的一种好方法是使用FOR XML PATH的XML功能。 看看这个问题:How to concatenate results in T-SQL into column?

答案 1 :(得分:0)

我很惊讶这种行为是设计的。

总结来自Martin链接的信息:不要像这样进行连接。即使没有order by,也无法保证工作。 要获得有保证的结果,请使用for xml

declare @stmt nvarchar(max) = '';
select @stmt = (select  
    'create index ' + ix.name + ' on ' + t.name 
    + isnull(' where ' + ix.filter_definition, '') + char(10)
    from tempdb.sys.tables t
    join tempdb.sys.indexes ix on t.object_id = ix.object_id
    where ix.type > 0 and t.name in ('t1','t2')
    order by ix.name
    for xml path(''));
print @stmt;

其他选项使用游标或SQLCLR。