SQL 查询 - 将结果连接成一个字符串 [重复]

Posted

技术标签:

【中文标题】SQL 查询 - 将结果连接成一个字符串 [重复]【英文标题】:SQL Query - Concatenating Results into One String [duplicate] 【发布时间】:2011-07-08 22:58:20 【问题描述】:

我有一个包含此代码的 sql 函数:

DECLARE @CodeNameString varchar(100)

SELECT CodeName FROM AccountCodes ORDER BY Sort

我需要将选择查询的所有结果连接到 CodeNameString。

显然,C# 代码中的 FOREACH 循环可以做到这一点,但我如何在 SQL 中做到这一点?

【问题讨论】:

SQL Server 的版本是什么?? SQL Server: Can I Comma Delimit Multiple Rows Into One Column? 和:***.com/questions/1817985/… 的可能重复 回答了很多次......但请注意,并非所有 FOR XML PATH 连接实现都能正确处理 XML 特殊字符( 等),就像我对先前答案的回答一样: ***.com/questions/5031204/… 【参考方案1】:
DECLARE @CodeNameString varchar(max)
SET @CodeNameString=''

SELECT @CodeNameString=@CodeNameString+CodeName FROM AccountCodes ORDER BY Sort
SELECT @CodeNameString

【讨论】:

简单而优雅的答案。使用这种方法有什么限制吗? (NULL 值由 James Wisemann 对此答案的变体处理)【参考方案2】:

@AlexanderMP 的回答是正确的,但你也可以考虑用coalesce 处理空值:

declare @CodeNameString  nvarchar(max)
set @CodeNameString = null
SELECT @CodeNameString = Coalesce(@CodeNameString + ', ', '') + cast(CodeName as varchar) from AccountCodes  
select @CodeNameString

【讨论】:

是的,我忘记了 coalesce/isnull。但是检查CodeName 而不是@CodeNameString 不是更有意义吗?这种方式可能会丢失数据。更好的是,使用普通的旧Where CodeName is not null 代替coaleste 是有意义的。 这绝对是最好最优雅的解决方案,非常感谢!【参考方案3】:

对于 SQL Server 2005 及更高版本,使用 Coalesce 表示 nulls,如果有 numeric values,我使用 Cast or Convert -

declare @CodeNameString  nvarchar(max)
select  @CodeNameString = COALESCE(@CodeNameString + ',', '')  + Cast(CodeName as varchar) from AccountCodes  ORDER BY Sort
select  @CodeNameString

【讨论】:

100 有点小,你不觉得吗;-) @James- 嗯..刚刚从 OP 的问题中复制了它,现在已经更新了..谢谢...顺便说一句,你确实打败了我..【参考方案4】:

如果您使用的是 SQL Server 2005 或更高版本,则可以使用此 FOR XML PATH & STUFF 技巧:

DECLARE @CodeNameString varchar(100)

SELECT 
   @CodeNameString = STUFF( (SELECT ',' + CodeName 
                             FROM dbo.AccountCodes 
                             ORDER BY Sort
                             FOR XML PATH('')), 
                            1, 1, '')

FOR XML PATH('') 基本上将您的字符串连接成一个长 XML 结果(类似于,code1,code2,code3 等),STUFF 在第一个字符处放置一个“无”字符,例如消除“多余的”第一个逗号,为您提供您可能正在寻找的结果。

更新: 好的 - 我了解 cmets - 如果您在数据库表中的文本已经包含 <>& 等字符,那么 我当前的解决方案 实际上会将它们编码为 <>&

如果您对该 XML 编码有疑问 - 那么是的,您必须查看 @KM 提出的解决方案,该解决方案也适用于这些字符。来自我的警告一句话:这种方法更多资源和处理密集型 - 如您所知。

【讨论】:

这将无法正确处理 XML 特殊字符(<&> 等),就像我之前的回答一样,请参见此处:@987654321 @ @marc_s 这很危险。我必须回应上面 KM 的评论。 @jnm2:同意 - 如果有人需要这些特殊字符,那么“KM”的解决方案就是要走的路。 但是:更多处理密集,因此我建议使用它,如果你真的必须在你的输出 @marc_s 对于大多数用例,您如何提前知道这些字符将来是否会出现?假设您不需要它们是危险的。您能否展示有关 KM 方法的文档会占用更多资源?我不明白为什么会这样。 @jnm2: 是的,我希望微软能够倾听并最终给我们一个内置(并优化!)函数来处理这个......【参考方案5】:

这是另一个现实生活中的例子,至少在 2008 版本(及更高版本)中运行良好。

这是原始查询,它使用简单的max() 来获取至少一个值:

SELECT option_name, Field_M3_name, max(Option_value) AS "Option value", max(Sorting) AS "Sorted"
FROM Value_list group by Option_name, Field_M3_name
ORDER BY option_name, Field_M3_name

改进版,主要改进是我们显示所有值以逗号分隔:

SELECT from1.keys, from1.option_name, from1.Field_M3_name,

 Stuff((SELECT DISTINCT ', ' + [Option_value] FROM Value_list from2
  WHERE COALESCE(from2.Option_name,'') + '|' + COALESCE(from2.Field_M3_name,'') = from1.keys FOR XML PATH(''),TYPE)
  .value('text()[1]','nvarchar(max)'),1,2,N'') AS "Option values",

 Stuff((SELECT DISTINCT ', ' + CAST([Sorting] AS VARCHAR) FROM Value_list from2
  WHERE COALESCE(from2.Option_name,'') + '|' + COALESCE(from2.Field_M3_name,'') = from1.keys FOR XML PATH(''),TYPE)
  .value('text()[1]','nvarchar(max)'),1,2,N'') AS "Sorting"

FROM ((SELECT DISTINCT COALESCE(Option_name,'') + '|' + COALESCE(Field_M3_name,'') AS keys, Option_name, Field_M3_name FROM Value_list)
-- WHERE
) from1
ORDER BY keys

请注意,我们已经解决了我能想到的所有可能的 NULL 案例问题,并且我们修复了我们收到的数值错误(字段排序)。

【讨论】:

【参考方案6】:

来自 msdn 不要在 SELECT 语句中使用变量来连接值(即计算聚合值)。可能会出现意外的查询结果。这是因为 SELECT 列表中的所有表达式(包括赋值)不能保证每个输出行都只执行一次

上面似乎是说,上面所做的连接是无效的,因为分配的执行次数可能比选择返回的行数多

【讨论】:

以上是关于SQL 查询 - 将结果连接成一个字符串 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

解析 SQL Server 查询而不针对数据库连接执行查询 [重复]

SQL group by 连接查询结果的字符串

连接多个表后如何从sql查询结果中删除重复记录

SQL查询结果拼接成字符串

SQL server 两个查询结果拼接成一个,语句改怎样修改?

在 Oracle 中连接 SQL 查询的结果