连接按列分组的值

Posted

技术标签:

【中文标题】连接按列分组的值【英文标题】:Concatenate values that are grouped by a column 【发布时间】:2015-04-24 13:33:51 【问题描述】:

我有下表:

Code    Ref     Value
A1      Car     A
A1      Car     -
A1      Car     B
B2      Truck   CC
B2      Truck   D
B2      Truck   -
C3      Van     E
C3      Van     F
C3      Van     -
C3      Van     G

我要实现的目标是一个连接字符串,将所有值组合在一起,如下所示:

Code   Ref    Value
A1     Car    A-B
B2     Truck  CCD-
C3     Van    EF-G

我离开了示例here,但一无所获。这是我想出的:

SELECT [Table].[Code]
, [Table].[Ref]
, STUFF((SELECT DISTINCT [Value]
  FROM [Table2]
  FOR XML PATH ('')),1, 1,'') AS Values
FROM [Table]
LEFT JOIN [Table2] ON
[Table2].[Code] = [Table].[Code]

我哪里错了?有没有更有效的方法来做到这一点?

【问题讨论】:

旁注:如果没有排序列,每次运行的串联结果可能(将)改变。这很重要吗? 现在不是。它们可以按任何顺序显示。 【参考方案1】:

您没有将您的内部和外部引用链接到[Table],并且您还需要使外部引用不同。最后,您需要在子查询中没有列名,或者必须是 [text()]

SELECT  [Code]
        ,[Ref]
        ,STUFF((SELECT DISTINCT [Value] AS [text()]
                FROM [Table] AS T2
                WHERE T1.Code = T2.Code -- LINK HERE
                AND T2.Ref = T2.Ref     -- AND HERE
                FOR XML PATH ('')
                ),1, 1,'') AS [Values]
FROM    [Table] AS T1
GROUP BY T1.Code, T1.Ref; -- GROUP BY HERE

顺便说一句,您不需要使用STUFF,因为您没有分隔符,STUFF 通常用于从字符串的开头删除选定的分隔符。所以当你有一个像,value1,value2,value3 这样的字符串时,STUFF(string, 1, 1, '') 将用'' 替换第一个字符,留下value1,value2,value3

您还应该使用value xquery 方法来确保您不会被特殊字符绊倒,如果您不这样做并且尝试连接">>""<<",您最终不会得到">><<"如您所愿,您会得到">><<",因此更好的查询是:

SELECT  t1.Code,
        t1.Ref,
        [Values] = (SELECT  DISTINCT [text()] = [Value]
                    FROM    [Table] AS t2
                    WHERE   T1.Code = T2.Code
                    AND     T2.Ref = T2.Ref
                    FOR XML PATH (''), TYPE
                ).value('.', 'NVARCHAR(MAX)')
FROM    [Table] AS T1
GROUP BY t1.Code, t1.Ref;

附录

根据对问题的最新编辑,您的Value 列似乎来自另一个表,由Code 链接到第一个表。如果有的话,这会使您的查询更简单。您不需要JOIN,但您仍然需要确保有一个表达式将外部表链接到您的子查询的内部表。我假设第一个表中的行是唯一的,因此您可能不需要 group by:

SELECT  t1.Code,
        t1.Ref,
        [Values] = (SELECT  DISTINCT [text()] = t2.[Value]
                    FROM    [Table2] AS t2
                    WHERE   T1.Code = T2.Code
                    FOR XML PATH (''), TYPE
                ).value('.', 'NVARCHAR(MAX)')
FROM    [Table] AS T1;

工作示例

CREATE TABLE #Table1 (Code CHAR(2), Ref VARCHAR(10));
INSERT #Table1 VALUES ('A1', 'Car'), ('B2', 'Truck'), ('C3', 'Van');

CREATE TABLE #Table2 (Code CHAR(2), Value VARCHAR(2));
INSERT #Table2
VALUES ('A1', 'A'), ('A1', '-'), ('A1', 'B'),
        ('B2', 'CC'), ('B2', 'D'), ('B2', '-'),
        ('C3', 'F'), ('C3', '-'), ('C3', 'G');

SELECT  t1.Code,
        t1.Ref,
        [Values] = (SELECT  DISTINCT [text()] = t2.[Value]
                    FROM    #Table2 AS t2
                    WHERE   T1.Code = T2.Code
                    FOR XML PATH (''), TYPE
                ).value('.', 'NVARCHAR(MAX)')
FROM    #Table1 AS T1;

【讨论】:

好的,这个工作正常了,现在如果t2 中有一个我需要订购的索引,我该怎么做呢?我收到错误消息“如果指定了 SELECT DISTINCT,则 ORDER BY 项目必须出现在选择列表中。”当我添加ORDER BY t2.Index 时,如果我弄清楚这部分,那就是我需要的答案。

以上是关于连接按列分组的值的主要内容,如果未能解决你的问题,请参考以下文章

MySQL:计算按列分组的值的中位数

在 xsl:fo 表中按列行值分组

SUM 值按列分组,但不能“聚合”?

按列值查询某些行的联合和分组

Querydsl:如何按列进行左连接

按列连接两个数据帧