SQLITE:如果共享一列,则将行合并为单行

时间:2011-10-23 16:19:50

标签: sql database sqlite aggregate-functions

在上一篇文章中,我在sqlite3中有以下视图:

CREATE View AttendeeTableView AS

SELECT  (LastName || " " || FirstName) as AttendeeName,  
        CompanyName, 
        PhotoURI,
        CompanyAttendeeRelation.CompanyId,
        CompanyAttendeeRelation.AttendeeId 

FROM    Attendee 
JOIN    CompanyAttendeeRelation on CompanyAttendeeRelation.AttendeeId = Attendee.AttendeeId 

ORDER BY LastName;

现在,由于数据是根据AttendeeCompany之间的多对多关系生成的,因此我可以获得以下结果:

Doe John | company A | johnPic.png | 1 | 15
Doe John | company B | johnPic.png | 2 | 15

我想做的是,如果有多家公司(如上所述),请创建一个输出查询:

Doe John | company A company B | johnPic.png | 1 2 | 15

另一个输出:

Doe John | company A | company B | johnPic.png | 1 | 2 | 15

所以我需要知道如何为具有不同行的行合并特定列 该表中的值。

有什么想法吗?

以防万一,第一个查询中的company A company B显然是文本连接,即(row1.CompanyName || " " || row2.CompanyName)

3 个答案:

答案 0 :(得分:10)

使用聚合函数 group_concat(X)

SELECT (a.LastName || " " || a.FirstName) AS AttendeeName
     , a.PhotoURI
     , group_concat(c.CompanyName) AS Companies
     , group_concat(c.CompanyId)   AS CompanyIds
FROM   Attendee AS a
JOIN   CompanyAttendeeRelation AS ca ON ca.AttendeeId = a.AttendeeId
JOIN   Company                 AS c  ON c.CompanyId = ca.CompanyId
GROUP  BY a.LastName, a.Firstname, a.PhotoURI;

(使用表别名使其更短更容易阅读。)

NULL值将从结果中排除。 The manual:

  

所有非NULL值的串联

根据the manualCompanyIdsCompanies中的元素顺序是任意的:

  

连接元素的顺序是任意的。

另请注意,“任意”与“随机”不同。与其他聚合函数一样,group_concat按接收顺序处理行集。没有任何ORDER BY,该顺序由执行的任何查询计划决定。关系数据库表中没有自然顺序(您不能完全依赖于的插入顺序)。但是同一group_concat()列表中SELECT的两个实例都按相同顺序处理行,以便CompanyIds中的第一个ID对应Companies中的第一个名称1}}。

您可以在子查询中使用ORDER BY强制执行订单。这是一个实现细节,但它不太可能改变。像:

SELECT (LastName || " " || FirstName) AS AttendeeName
     , PhotoURI
     , group_concat(CompanyName) AS Companies
     , group_concat(CompanyId)   AS CompanyIds
FROM  (
   SELECT a.LastName, a.FirstName, a.PhotoURI, c.CompanyName, c.CompanyId
   FROM   Attendee AS a
   JOIN   CompanyAttendeeRelation AS ca ON ca.AttendeeId = a.AttendeeId
   JOIN   Company                 AS c  ON c.CompanyId = ca.CompanyId
   ORDER  BY 1,2,3,4,5  -- or whatever you need
   ) AS sub
GROUP  BY LastName, Firstname, PhotoURI;

The manual关于ORDER BY中的(可选)序号:

  

如果ORDER BY表达式是一个常数整数K,则该表达式被视为结果集的第K列的别名(列从左到右编号,从1开始)。

使用GROUP BY列表作为前导ORDER BY表达式,以获得最佳效果。

在排序之后不要对派生表做任何可能重新排列的事情(比如将子查询加入到另一个表等)。

最后,请注意其他RDBMS中的类似聚合函数的行为可能略有不同。相关:

答案 1 :(得分:2)

this post的答案将帮助您转向

Name     | company
---------+----------
Doe John | company A
Doe John | company B

进入

Name     | company-1 | company-2
---------+-----------+----------
Doe John | company A | company B

答案 2 :(得分:1)

我认为内部选择可能会有所帮助,例如:

CREATE View AttendeeTableView AS

SELECT  (LastName || " " || FirstName) as AttendeeName,  

(
  select CompanyName
FROM    Attendee A_innner 
JOIN    CompanyAttendeeRelation CAR  /* is this where company name is? */  
ON      on CAR.AttendeeId = A.AttendeeId /* if not remove the joins and CAR */
WHERE   A_inner.last_name = A_outer.last_name and
        A_inner.first_name = A_outer.first_name
),
PhotoURI,
CAR.CompanyId,
CAR.AttendeeId 


FROM    Attendee A_outer 
JOIN    CompanyAttendeeRelation CAR_outer  
ON      on CAR_outer.AttendeeId = A_outer.AttendeeId 

GROUP by LastName,FirstName
ORDER BY LastName, FirstName;