如何在一个查询中的多个子查询上正确使用多个 group_concats 而没有区别?
Posted
技术标签:
【中文标题】如何在一个查询中的多个子查询上正确使用多个 group_concats 而没有区别?【英文标题】:How do you properly use multiple group_concats on multiple subqueries within one query without distinct? 【发布时间】:2021-03-12 22:32:41 【问题描述】:我有一个相当可怕的查询,我正在为特定用户或多个用户提取信息。我需要为该用户获取多组标准化属性,以便通过每个链接表进行访问。
我想将这些集合作为逗号分隔的列表拉回,这似乎是 group_concat 构建的,但我不断得到大量额外的结果,每个额外的连接都会增加。虽然我想我知道原因,但我很难想象如何构建查询以避免这种情况。
我创建了一个简化版本的我在小提琴here 中尝试做的事情。如果该链接不可用,这里是 DDL:
CREATE TABLE users (ID INT, name VARCHAR(30));
INSERT INTO users (ID, name)
VALUES (1, 'Jon');
INSERT INTO users (ID, name)
VALUES (2, 'Jane');
CREATE TABLE skills (ID INT, name VARCHAR(30), groupName VARCHAR(30));
INSERT INTO skills (ID, name, groupName)
VALUES (1, 'Drawing', 'Art');
INSERT INTO skills (ID, name, groupName)
VALUES (2, '3D Animation', 'Art');
INSERT INTO skills (ID, name, groupName)
VALUES (3, 'javascript', 'Programming');
INSERT INTO skills (ID, name, groupName)
VALUES (4, 'html', 'Programming');
CREATE TABLE users2skills (UID INT, SID INT);
INSERT INTO users2skills (UID, SID)
VALUES (1, 3);
INSERT INTO users2skills (UID, SID)
VALUES (1, 4);
INSERT INTO users2skills (UID, SID)
VALUES (2, 1);
INSERT INTO users2skills (UID, SID)
VALUES (2, 2);
INSERT INTO users2skills (UID, SID)
VALUES (2, 4);
CREATE TABLE shifts (ID INT, name VARCHAR(30));
INSERT INTO shifts (ID, name)
VALUES (1, 'Daylight');
INSERT INTO shifts (ID, name)
VALUES (2, 'Evening');
INSERT INTO shifts (ID, name)
VALUES (3, 'Midnight');
CREATE TABLE users2shifts (UID INT, SID INT);
INSERT INTO users2shifts (UID, SID)
VALUES (1, 1);
INSERT INTO users2shifts (UID, SID)
VALUES (1, 2);
INSERT INTO users2shifts (UID, SID)
VALUES (2, 2);
INSERT INTO users2shifts (UID, SID)
VALUES (2, 3);
首先,这是我汇总的一个简单查询,它得出了预期的结果:
select u.ID,
u.name,
GROUP_CONCAT(skQ.ID order by skQ.ID) as skillList,
GROUP_CONCAT(skQ.name order by skQ.ID) as skillDesc
from users u
left outer join (
select u2sk.UID, sk.ID, sk.name
from users2skills u2sk
inner join skills sk on sk.ID = u2sk.SID
) skQ on skQ.UID = u.ID
group by u.ID,
u.name
结果如下所示:
ID name skillList skillDesc
1 Jon 3,4 javaScript,HTML
2 Jane 1,2,4 Drawing,3D Animation,HTML
请注意,两个列表的顺序匹配,因此我可以稍后以编程方式将 ID 加入到描述中。但是,我需要额外的数据,包括技能的类别描述,并且想要一个看起来像这样的最终结果集:
ID name skillList skillDesc skillGroups shiftList shiftDesc
1 Jon 3,4 javaScript,HTML Programming,Programming 1,2 Daylight,Evening
2 Jane 1,2,4 Drawing,3D Animation,HTML Art,Art,Programming 2,3 Evening,Midnight
所以我为我希望加入的新表添加了几个新的 group_concat 语句,创建了这个查询:
select u.ID,
u.name,
GROUP_CONCAT(skQ.ID order by skQ.ID) as skillList,
GROUP_CONCAT(skQ.name order by skQ.ID) as skillDesc,
GROUP_CONCAT(skQ.groupName order by skQ.ID) as skillGroups,
GROUP_CONCAT(shQ.ID order by skQ.ID) as shiftList,
GROUP_CONCAT(shQ.name order by skQ.ID) as shiftDesc
from users u
left outer join (
select u2sk.UID, sk.ID, sk.name, sk.groupName
from users2skills u2sk
inner join skills sk on sk.ID = u2sk.SID
) skQ on skQ.UID = u.ID
left outer join (
select u2sh.UID, sh.ID, sh.name
from users2shifts u2sh
inner join shifts sh on sh.ID = u2sh.SID
) shQ on shQ.UID = u.ID
group by u.ID,
u.name
但是,那返回的结果集是:
ID name skillList skillDesc skillGroups shiftList shiftDesc
1 Jon 3,3,4,4 javaScript,javaScript,HTML,HTML Programming,Programming,Programming,Programming 2,1,2,1 Evening,Daylight,Evening,Daylight
2 Jane 1,1,2,2,4,4 Drawing,Drawing,3D Animation,3D Animation,HTML,HTML Art,Art,Art,Art,Programming,Programming 3,2,3,2,3,2 Midnight,Evening,Midnight,Evening,Midnight,Evening
在我的实际查询中,这个问题成倍增加,每个列表包含 100 多个项目。我已经看到了很多关于如何解决这个问题的问题,但我发现一般都会得到相同的答案:使用 distinct。这给我带来了一个问题,因为我在“groupName”字段中有重复的值,这些值被不同的过滤掉了。这会导致列表大小不同,并阻止我在取回数据后对其进行任何处理。
如果我能提供帮助,我宁愿不需要进行十个单独的查询,以及 Web 和 DB 服务器之间的所有相关开销和连接。我怀疑一个查询无论如何都会快得多。以我需要的格式获取所需数据的正确方法是什么?
【问题讨论】:
FWIW,我认为数据显示的问题最好在应用程序代码中解决 @Strawberry 我自己也开始按照这些思路进行思考。但在这一点上,我真的很想知道我决定去的任何一种方式的解决方案,因为我已经投入了太多时间,至少不能离开一堂课。 好吧,也许这就是教训 【参考方案1】:两个left join
ed 表中有多个匹配主表中的给定行,因此行被相乘,并且您最终得到相同的值被多次聚合。
基本上,你需要在子查询中聚合:
select u.ID, u.name, skQ.skillList, skQ.skillDesc, sqQ.skillGroups, shQ.shiftList, shQ.shiftDesc
from users u
left outer join (
select u2sk.UID,
GROUP_CONCAT(sk.ID order by sk.ID) as skillList
GROUP_CONCAT(sk.name order by sk.ID) as skillDesc,
GROUP_CONCAT(sk.groupName order by sk.ID) as skillGroups
from users2skills u2sk
inner join skills sk on sk.ID = u2sk.SID
group by u2sk.uid
) skQ on skQ.UID = u.ID
left outer join (
select u2sh.UID,
GROUP_CONCAT(sh.ID order by sh.ID) as shiftList,
GROUP_CONCAT(sh.name order by sh.ID) as shiftDesc
from users2shifts u2sh
inner join shifts sh on sh.ID = u2sh.SID
) shQ on shQ.UID = u.ID
【讨论】:
谢谢。这很有意义,并且按预期工作。以上是关于如何在一个查询中的多个子查询上正确使用多个 group_concats 而没有区别?的主要内容,如果未能解决你的问题,请参考以下文章
为来自不同表的两个单独操作运行多个子查询(相关)并加入一个表[关闭]