SELECT查询的连接结果仅返回一个值

时间:2013-08-12 13:36:26

标签: sql-server tsql stored-procedures

我正在使用一个select查询和一个变量,以便从查询中连接一些字符串,如下所示:

DECLARE @sConcat nvarchar(max)
SET @sConcat = ''
SELECT @sConcat = @sConcat + '[' + SomeColumn + ']'
 FROM SomeTable
 ORDER BY SomeColumn

在我的特定情况下,我将FROM子句更改为派生表,该表只是将整数列强制转换为nvarchar,这样我就不必每次在连接中出现它。

进行此更改后,连接的结果只是表格中的一个值。将CAST移动到外部查询或删除ORDER BY子句时,结果与预期一致。

这一切都可以用以下的t-sql重现。

BEGIN TRAN

-- Create a dummy table and populate it with some values
CREATE TABLE TTest (
    TTest_ID int IDENTITY(1,1) NOT NULL,
    TTest_Text varchar(8) NOT NULL
 CONSTRAINT PK_TTest PRIMARY KEY CLUSTERED (
    TTest_Id ASC
 )
) ON [PRIMARY]

INSERT INTO TTest (TTest_Text) VALUES ('A')
INSERT INTO TTest (TTest_Text) VALUES ('B')
INSERT INTO TTest (TTest_Text) VALUES ('C')
INSERT INTO TTest (TTest_Text) VALUES ('D')
INSERT INTO TTest (TTest_Text) VALUES ('E')
INSERT INTO TTest (TTest_Text) VALUES ('F')
INSERT INTO TTest (TTest_Text) VALUES ('G')
INSERT INTO TTest (TTest_Text) VALUES ('H')

-- Create a string with the ID values of each row in brackets
DECLARE @sConcat nvarchar(max)

-- First attempt, produces the result '[8]' which is not what I expected
SET @sConcat = ''
SELECT @sConcat = @sConcat + '[' + TTest_ID + ']'
 FROM  (SELECT CAST(TTest_ID AS nvarchar(100)) AS TTest_ID, TTest_Text
         FROM TTest) TTestBis
 ORDER BY TTestBis.TTest_ID ASC

PRINT @sConcat

-- Second attempt, with cast in the outer query, 
-- produces the expected result '[1][2][3][4][5][6][7][8]'
SET @sConcat = ''
SELECT @sConcat = @sConcat + '[' + CAST(TTest_ID AS nvarchar(100)) + ']'
 FROM  (SELECT TTest_ID, TTest_Text
         FROM TTest) TTestBis
 ORDER BY TTestBis.TTest_ID ASC

PRINT @sConcat

-- Third attempt, same as first but without ORDER BY, 
-- also produces the expected result '[1][2][3][4][5][6][7][8]'
SET @sConcat = ''
SELECT @sConcat = @sConcat + '[' + TTest_ID + ']'
 FROM  (SELECT CAST(TTest_ID AS nvarchar(100)) AS TTest_ID, TTest_Text
         FROM TTest) TTestBis

PRINT @sConcat

ROLLBACK

为什么SQL Server会以这种方式运行?对我来说没有意义。我在SQL Server 2005,2008和2008R2上重现了这一点。

修改

这个问题确实是重复的。到目前为止给出的最佳答案似乎是马丁史密斯in this question。所以你可以投票结束。

2 个答案:

答案 0 :(得分:0)

问题确实是重复的。可以在以下stackoverflow问题中找到全面的答案:nvarchar concatenation / index / nvarchar(max) inexplicable behavior

本文提供了几种解决SELECT查询中串联字符串问题的有效解决方案:https://www.simple-talk.com/sql/t-sql-programming/concatenating-row-values-in-transact-sql/

答案 1 :(得分:-1)

哇!乍一看,您可能会认为这是一个错误。经过多次分析后,我的意见如下

我在SQL Server 2012开发人员版本中完成了所有测试。我们去查询计划学校

- 典型的顺序=排序操作
从TTest中选择* 按TTest_Text desc排序;


enter image description here

- 代码1
DECLARE @sConcat nvarchar(max)='';
SELECT @sConcat = @sConcat +'['+ D1.TTest_ID2 +']'
来自   (SELECT CAST(TTest_ID AS nvarchar(100))AS TTest_ID2,TTest_Text FROM TTest)D1
ORDER BY D1.TTest_ID2;
PRINT @sConcat;


enter image description here

这会产生看起来正确但结果错误的计划。

- 代码2
DECLARE @sConcat nvarchar(max)='';
SELECT @sConcat = @sConcat +'['+ CAST(D2.TTest_ID AS nvarchar(100))+']'
FROM(SELECT TTest_ID,TTest_Text FROM TTest)D2
ORDER BY D2.TTest_ID ASC;
打印@sConcat;

enter image description here

这会产生一个没有排序,错误计划但是结果正确的计划

我认为你真的需要考虑SQL解释请求的逻辑方式。

1 - 来自 2 - 在哪里 3 - GROUP BY
4 - 有 5 - 选择
6 - 订购

因此,首先计算派生查询。由于以下限制,我们无法订购子查询:

ORDER BY子句在视图,内联函数,派生表,子查询和公用表表达式中无效,除非还指定了TOP,OFFSET或FOR XML。

有人会认为(查询优化器/事务管理器)会计算字符串,然后注意它不能排序,因为你有N行而是1个结果。

简而言之,人们希望这两个查询都能正常工作或失败。因为他们没有得到相同的计划,所以一个查询起作用而另一个查询不起作用。