在列中组合多个行值以进行分组

时间:2014-09-18 16:21:25

标签: sql sql-server sql-server-2008 sql-server-2012

我的表有以下内容:


I   Place   ID
1   KARNATAKA   3         
2   KARNATAKA   5         
3   ANDHRA  3         
4   ANDHRA  4         
9   TAMILNADU   2         
6   TAMILNADU   5         
7   TAMILNADU   1         
8   TAMILNADU   4    

另一张表:

Id  FirstName   SecondName
1           Ram         N         
2           Sita        K         
3           Bootha      MU        
4           Krishnan    S         
5           Hari        M         
6           Mehta       A         
7           Rahul       C         
8           Vamsi       M         
9           Badri       S   

我正在寻找以下输出:

Place    FirstName
KARNATAKA    Bootha, Hari
ANDHRA       Bootha, Krishnan

同样是第三排。

基本上,它在第二列中结合了“STUFFS”。

我尝试下面的查询,但它不起作用。

select ad.Place, STUFF((SELECT ', '+ FirstName FROM Associate a INNER JOIN Address Ad on a.Id = Ad.ID 
FOR XML PATH ('')) , 1, 1, '') 
From Address ad inner join Associate a
on ad.ID = a.Id
group by ad.Place

只需稍加修正,请帮帮我?

2 个答案:

答案 0 :(得分:3)

问题是你有太多的联接。这很棘手,因为两个表之间的连接是id,但是您在不同级别进行聚合。因此,在子查询中确实需要join和相关条件:

select ad.Place,
       STUFF((SELECT ', ' + a.FirstName
              FROM Associate a join
                   Address ad2
                   on a.Id = ad2.Id
              WHERE ad2.Place = ad.Place
              FOR XML PATH ('')
             ) , 1, 2, '') 
From Address ad
group by ad.Place;

作为次要问题,您对stuff()1, 1)的参数会在连接字符串的开头留一个空格。

答案 1 :(得分:0)

首先,我建议您规范化数据库架构。实际上,您在存储地名的第一个表中有一些冗余。我建议你在一个表中记录位置,在另一个表中记录人物,在单独的N:N链接表中记录人物和地点之间的关系:

CREATE TABLE Place
(
    Id INT NOT NULL PRIMARY KEY,
    Name NVARCHAR(50) NOT NULL
);

CREATE TABLE Person
(
    Id INT NOT NULL PRIMARY KEY,
    Name NVARCHAR(50) NOT NULL
);

CREATE TABLE PersonAtPlace
(
    PersonId INT NOT NULL REFERENCES Person (Id),
    PlaceId INT NOT NULL REFERENCES Place (Id),
    PRIMARY KEY (PersonId, PlaceId)
);

现在针对按地点汇总人员的问题,您实际上并不需要GROUP BY子句。试试这个:

SELECT pl.Name,
       COALESCE(STUFF((SELECT DISTINCT ', ' + pn.Name
                       FROM PersonAtPlace plXpn
                       INNER JOIN Person pn ON pn.Id = plXpn.PersonId
                       WHERE plXpn.PlaceId = pl.Id
                       ORDER BY ', ' + pn.Name -- this is optional
                       FOR XML PATH('')), 1, 1, ''), '') AS People
FROM Place pl;

以下是有关如何阅读此查询的一些指导:

  • 外部SELECT的唯一目的是为每个地方生成一行(因为您正在为每个地方创建一个摘要 ),并且可以引用它放在内部查询中。

  • 内部查询执行人员摘要(通过将其名称连接成以逗号分隔的列表字符串)。

    • 我们从表示所有人与人之间关系的链接表开始。
    • 使用WHERE子句,我们会过滤掉所有不属于我们当前正在总结的地方的记录(即pl来自外部SELECT)。< / LI>
    • 需要JOIN才能找到某个人的姓名。
    • GROUP BY是可选的,但如果存在,则确保对逗号分隔列表中的名称进行排序。
    • 您已经知道STUFF … FOR XML PATH的作用:将名称连接成以逗号分隔的列表字符串。