SQLITE:如果它们共享一列,则将行合并为单行
Posted
技术标签:
【中文标题】SQLITE:如果它们共享一列,则将行合并为单行【英文标题】:SQLITE: merging rows into single row if they share a column 【发布时间】:2011-12-13 14:55:33 【问题描述】:从上一篇文章中,我在 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;
现在,由于数据是从Attendee
和Company
之间的多对多关系生成的,我可以得到如下结果:
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)
的内容
【问题讨论】:
【参考方案1】:为此使用聚合函数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:
所有非空值的串联
CompanyIds
和Companies
中的元素顺序是任意的,根据the manual:
连接元素的顺序是任意的。
另请注意,“任意”与“随机”不同。 group_concat
与其他聚合函数一样,按接收顺序处理行集。如果没有任何ORDER BY
,则该顺序由执行的任何查询计划决定。关系数据库的表中没有自然顺序(您不能完全依赖插入顺序)。但是group_concat()
的两个实例在同一SELECT
中以相同 的顺序列出进程行,因此CompanyIds
中的第一个ID 对应于Companies
中的第一个名称。
您可以在子查询中使用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 中类似的聚合函数的行为可能略有不同。相关:
Concatenate multiple result rows of one column into one, group by another column GROUP_CONCAT ORDER BY【讨论】:
手册说The order of the concatenated elements is arbitrary
。这是否意味着串联的CompanyIds
不一定按照Companies
的顺序匹配?
@Jason:我添加了更多来解决这个问题(除其他外)。【参考方案2】:
this post的回答会帮你转
Name | company
---------+----------
Doe John | company A
Doe John | company B
进入
Name | company-1 | company-2
---------+-----------+----------
Doe John | company A | company B
【讨论】:
【参考方案3】:我认为内部选择可能会有所帮助,例如:
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;
【讨论】:
以上是关于SQLITE:如果它们共享一列,则将行合并为单行的主要内容,如果未能解决你的问题,请参考以下文章
Python - 如果 DOB 和 Address1 和 Address2 和 PostCode 为 NULL,则将行作为 Badrecord 移动到新数据帧