【问题标题】:Sql concatenation not working with case statement in sqlSql 连接不适用于 sql 中的 case 语句
【发布时间】:2014-08-18 12:50:13
【问题描述】:

我想将多行连接成一个文本字符串,但也想使用 case 语句检查几个条件。我的查询总是返回最后一个值,而不是连接所有值。

我的sql查询如下

DECLARE @str varchar(1000)
SET @str = ''
SELECT @str = @str + 
     CASE WHEN SUBSTRING(value,CHARINDEX('|',value)+1,LEN(value)) <> '' THEN 
         '$' +REPLACE(value,'|',' - ')
     ELSE 
         '$' +ISNULL(REPLACE(value,'|',''),'') 
     END + ', ' 
FROM dbo.sometable          

print @str

【问题讨论】:

  • 这当然是一种方法:我会使用 VARCHAR(MAX) 而不是 VARCHAR(1000) 并按原样(或使用 COALESCE)连接 VALUE 字段以检查它是工作,然后添加您的 CASE 逻辑。
  • 让我抓狂的是MS无法或不愿意在TSQL中提供CONCAT(column, separator)聚合函数!由于同样的反复出现的问题,损失了很多工作时间!

标签: sql-server tsql


【解决方案1】:

您的代码有效:

--I added this
DECLARE @str varchar(1000)
declare @sometable table (value varchar(50))
insert into @sometable values ('aaaa|bbbb|cccc|dddd')
insert into @sometable values ('1111|2222|3333|4444')
insert into @sometable values ('xx|yy|zz')

--your code unchanged, other than "dbo.sometable" to "@sometable"
SET @str = ''
SELECT @str = @str + 
     CASE WHEN SUBSTRING(value,CHARINDEX('|',value)+1,LEN(value)) <> '' THEN 
         '$' +REPLACE(value,'|',' - ')
     ELSE 
         '$' +ISNULL(REPLACE(value,'|',''),'') 
     END + ', ' 
FROM @sometable --<<only changed table name         

print @str

输出:

$aaaa - bbbb - cccc - dddd, $1111 - 2222 - 3333 - 4444, $xx - yy - zz, 

我认为你的连接看起来不错,运行它来检查你的查询不只是错误:

SELECT value
FROM dbo.sometable 

如果您在实际查询中有更多详细信息,您可能有一个不好的where 或加入。

---- 编辑----

此外,以这种方式连接时,您不能在查询中使用 ORDER BY 如果您需要与 order by 连接,您可以使用类似这样的内容:

set nocount on;
declare @YourTable table (RowID int, HeaderValue int, ChildValue varchar(5))
insert into @YourTable VALUES (4,3,'<br>')
insert into @YourTable VALUES (1,1,'CCC')
insert into @YourTable VALUES (3,2,'AAA')
insert into @YourTable VALUES (5,3,'A & Z')
insert into @YourTable VALUES (2,2,'B<&>B')

set nocount off
SELECT
    t1.HeaderValue
        ,STUFF(
                   (SELECT
                        ', ' + t2.ChildValue
                        FROM @YourTable t2
                        WHERE t1.HeaderValue=t2.HeaderValue
                        ORDER BY t2.ChildValue --<<<<<<<<<<<<ORDER BY
                        FOR XML PATH(''), TYPE
                   ).value('.','varchar(max)')
                   ,1,2, ''
              ) AS ChildValues
    FROM @YourTable t1
    GROUP BY t1.HeaderValue

输出:

HeaderValue ChildValues
----------- ---------------
1           CCC
2           AAA, B<&>B
3           <br>, A & Z

(3 row(s) affected)

这是您的代码的一个工作示例:

DECLARE @str varchar(1000)
declare @sometable table (value varchar(50))
insert into @sometable values ('aaaa|bbbb|cccc|dddd')
insert into @sometable values ('1111|2222|3333|4444')
insert into @sometable values ('xx|yy|zz')

--your code unchanged, other than "dbo.sometable" to "@sometable"
SET @str = ''
SELECT @str = @str + STUFF(
                               (SELECT  ', ' +
                                         CASE WHEN SUBSTRING(value,CHARINDEX('|',value)+1,LEN(value)) <> '' THEN 
                                             '$' +REPLACE(value,'|',' - ')
                                         ELSE 
                                             '$' +ISNULL(REPLACE(value,'|',''),'') 
                                         END 
                                    FROM @sometable t2

                                    ORDER BY t2.value --<<<<<<<<<<<<ORDER BY
                                    FOR XML PATH(''), TYPE
                               ).value('.','varchar(max)')
                               ,1,2, ''
                          ) 



print @str

输出:

$1111 - 2222 - 3333 - 4444, $aaaa - bbbb - cccc - dddd, $xx - yy - zz

【讨论】:

  • 如果您不介意在月相变化、数据量变化等情况下突然停止工作,代码“工作”。见Remarks:“不要在用于连接值(即计算聚合值)的 SELECT 语句。可能会出现意外的查询结果。这是因为 SELECT 列表中的所有表达式(包括赋值)不能保证每个输出行都只执行一次”跨度>
  • @ Damien_The_Unbeliever,通过阅读该链接,我认为您只有在使用ORDER BY 时才会遇到问题,而这里的情况并非如此。在最近的 XML 技巧之前,这种连接方法已经使用了多年:stackoverflow.com/a/7284932/65223
  • @KM - 您可以选择说“它仅适用于涉及ORDER BY 的情况”,但我确信我已经看到了没有ORDER BY 就失败的例子。文档中的建议是“不要这样做”。知识库文章演示了 一种 无法保证的方式。
【解决方案2】:

在 SQL Server 中进行行连接最常见的方法是使用FOR XML PATH

SELECT @str = STUFF((SELECT CASE WHEN SUBSTRING(value,CHARINDEX('|',value)+1,LEN(value)) <> '' 
                          THEN '$' +REPLACE(value,'|',' - ')
                          ELSE '$' +ISNULL(REPLACE(value,'|',''),'') 
                     END 
              FROM @t FOR XML PATH('')), 1, 1, '')

【讨论】:

  • 这不适用于包含&amp;&lt; 等字符的数据。我的答案中的 XML 连接示例略有不同,适用于这些字符。
  • @KM。不知道这一点,刚刚访问并添加了您的回答上述帖子的收藏夹。感谢您的回答 +1。
猜你喜欢
  • 1970-01-01
  • 2016-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-07
  • 1970-01-01
  • 1970-01-01
  • 2013-03-23
相关资源
最近更新 更多