如何将多个列“内爆”(去标准化/连接)到一个列中?

时间:2011-11-10 19:12:34

标签: sql-server tsql concatenation

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

+-------+----+--------------+
| 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

任何想法都表示赞赏!

4 个答案:

答案 0 :(得分: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)

答案 1 :(得分:1)

您可以使用以下功能轻松完成: 假设您将一直搜索同一列/表。如果您希望能够改变列/表

,则需要动态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

答案 2 :(得分:0)

您可以使用here描述的技术。 (完全披露:那是我的博客。)它讨论了在不使用游标的情况下在T-SQL中生成连接字符串。

答案 3 :(得分:0)

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