如何将多列“爆破”(反规范化/合并)成一列?

Posted

技术标签:

【中文标题】如何将多列“爆破”(反规范化/合并)成一列?【英文标题】:How to "Implode" (de-normalize/concat) multiple columns into a single column? 【发布时间】:2011-12-26 11:11:33 【问题描述】:

我有一个查询,它输出如下内容:

+-------+----+--------------+
| F_KEY | EV | OTHER_COLUMN |
+-------+----+--------------+
| 100   | 1  | ...          |
| 100   | 2  | ...          |
| 150   | 2  | ...          |
| 100   | 3  | ...          |
| 150   | 4  | ...          |
+-------+----+--------------+

我确信我已经看到了一个聚合函数,它将它(使用GROUP BY F_KEY)变成了这样的东西:

+-------+------------+--------------+
| F_KEY | ?          | OTHER_COLUMN |
+-------+------------+--------------+
| 100   | (1, 2, 3)  | ...          |
| 150   | (2, 4)     | ...          |
+-------+------------+--------------+

意味着,它以某种方式将EV 的值“内爆”到一个字段中。我怎样才能做到这一点?不幸的是,我不记得函数的名称了。

我正在使用 SQL Server。

这是我的查询的简化:

SELECT
    F_KEY,
    EV,
    OTHER_COLUMN
FROM
    TABLE1
JOIN
    TABLE2 ON F_KEY = TABLE2.ID
WHERE
    EVENT_TIME BETWEEN '2011-01-01 00:00:00.000' AND '2011-12-31 23:59:59.999'
ORDER BY
    EVENT_TIME ASC

任何想法都值得赞赏!

【问题讨论】:

遗憾的是,SQL Server 中没有内置这样的功能。 PIVOT 操作符的行为是这样的,但每个值最终会出现在自己的列中,而不是连接在一起。您需要编写一个相当复杂的函数来执行您所描述的内容。 @Philip Kelley Aww,最多只有一两个光标;-) arr... 我知道它存在。但不是在 SQL Server 中......它在 mysql 中并称为GROUP_CONCAT,它在 SQL Server 中不存在。必须找到解决方法=( 确实,只是一个游标和插入/附加到临时表。不幸的是,我从来没有写过游标,所以我不能写出来:D Simulating group_concat MySQL function in MS SQL Server 2005? 的可能重复项(以及 很多 个其他项) 【参考方案1】:

您可能可以使用here 中描述的技术。 (完全公开:那是我的博客。)它谈到在 T-SQL 中生成连接字符串,而不使用游标。

【讨论】:

这很聪明也很简单:ISNULL(str1 + ' ', '') + ISNULL(str2 + ' ', '') + ISNULL(str3, '')【参考方案2】:

这里是最好的连接方法,它不会像其他 XML 方法那样扩展特殊字符:

--Concatenation with FOR XML & eliminating control/encoded char expansion "& < >"
set nocount on;
declare @YourTable table (RowID int, HeaderValue int, ChildValue varchar(5))
insert into @YourTable VALUES (1,1,'CCC')
insert into @YourTable VALUES (2,2,'B<&>B')
insert into @YourTable VALUES (3,2,'AAA')
insert into @YourTable VALUES (4,3,'<br>')
insert into @YourTable VALUES (5,3,'A & Z')
set nocount off
SELECT
    t1.HeaderValue
        ,STUFF(
                   (SELECT
                        ', ' + t2.ChildValue
                        FROM @YourTable t2
                        WHERE t1.HeaderValue=t2.HeaderValue
                        ORDER BY t2.ChildValue
                        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)

【讨论】:

【参考方案3】:

您可以使用以下函数轻松完成: 假设您将一直搜索相同的列/表。如果您希望能够改变列/表,则需要动态 SQL

CREATE FUNCTION [dbo].[fn_recursion]
(@F_KEY int)  
RETURNS varchar(2000) AS 
BEGIN 

    DECLARE @ReturnVal Varchar(2000)

    SELECT @ReturnVal = COALESCE(@ReturnVal + ', ', '') + EV
    FROM TABLE2 
    WHERE @F_KEY = @F_KEY

    RETURN ISNULL(@ReturnVal,'')

END
GO


SELECT
    F_KEY,
    EV = [dbo].[fn_recursion](F_KEY),
    OTHER_COLUMN
FROM
    TABLE1
JOIN
    TABLE2 ON F_KEY = TABLE2.ID
WHERE
    EVENT_TIME BETWEEN '2011-01-01 00:00:00.000' AND '2011-12-31 23:59:59.999'
ORDER BY
    EVENT_TIME ASC

GO

DROP FUNCTION [dbo].[fn_recursion]
GO

【讨论】:

【参考方案4】:

查看使用 FOR XML PATH,您可以像 varchar 一样使用 xml 字符串转换它,这也支持分隔字符/表达式。它会在您的查询结束时执行,但很可能需要您使用子查询结构。

【讨论】:

以上是关于如何将多列“爆破”(反规范化/合并)成一列?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用R将多列堆叠成一列[重复]

Excel如何把一列数据拆成多列

excel多列文字合并成一列的方法都有哪些步骤

BigQuery - 将多列连接成一列以获取大量列

将多列合并为一列

C#将查询返回的数据(一行多列)怎么转换成一列多行dataTable?