sql - Listagg 两列 + 共享相同值时将它们分组
问题描述
我正在开发 Oracle SQL-Developer。
让我们从数据开始,以更好地描述我的问题。我有一个有 2 列的表
USER
JOB
这两个之间的关系是1,n。因此,1 个用户可以与 1 个或多个 JOB 相关,1 个 JOB 与 1 个或多个 USER 相关。
这里是数据样本:
USER JOB
1 A
1 B
1 C
1 D
1 E
2 B
2 C
2 F
2 G
3 A
3 B
3 C
3 D
4 I
4 J
4 K
4 L
这个想法是一起检索相互关联的值。首先,我认为 LISTAGG 可以连接和分组值。但我得到了这种结果:
USER JOB
1 A, B, C, D, E
2 B, C, F, G
3 A, B, C, D
4 I, J, K, L
或者
USER JOB
1, 3 A
1, 2, 3 B
1, 2, 3 C
1, 3 D
1 E
2 F
2 G
4 I
4 J
4 K
4 L
所需的输出如下:
USER JOB
1, 2, 3 A, B, C, D, E, F, G
4 I, J, K, L
这个想法是,如果一个用户与其他人共享一份工作,那么所有工作都链接在一起,即使所有工作都不相同。
示例:USER_1
有 2 个工作 A 和 B。USER_2
有 2 个工作 B 和 C。然后USER_1
共享USER_2
工作 A、B、C。
相反,如果一个工作与另一个工作共享一个用户,那么所有用户都链接在一起,即使所有用户都不相同......
因此,我尝试了自我加入,以便检索一个给定用户的所有工作和给定一个工作的所有用户,以显示所有可能的共享值,但也许这是错误的方式,因为我仍然被 LISTAGG 阻止。我也考虑过 PIVOT,但还没有尝试过。
我希望我说清楚了。大家怎么看?
解决方案
这对于大型数据集效率不高,但您可以使用分层查询来查找每个组所属的组,然后在每个组中找到不同的用户/作业,然后聚合:
WITH groups ( grp, "USER", job ) AS (
SELECT MIN(CONNECT_BY_ROOT("USER")) AS grp,
"USER",
JOB
FROM table_name
CONNECT BY NOCYCLE
PRIOR "USER" = "USER"
OR PRIOR JOB = JOB
GROUP BY "USER", JOB
)
SELECT users,
jobs
FROM (
SELECT grp,
LISTAGG("USER", ',') WITHIN GROUP (ORDER BY "USER") AS users
FROM (
SELECT DISTINCT grp, "USER"
FROM groups
)
GROUP BY grp
) u
INNER JOIN
(
SELECT grp,
LISTAGG(JOB, ',') WITHIN GROUP (ORDER BY JOB) AS jobs
FROM (
SELECT DISTINCT grp, job
FROM groups
)
GROUP BY grp
) j
ON ( u.grp = j.grp );
其中,对于您的示例数据:
CREATE TABLE table_name ( "USER", JOB ) AS
SELECT 1, 'A' FROM DUAL UNION ALL
SELECT 1, 'B' FROM DUAL UNION ALL
SELECT 1, 'C' FROM DUAL UNION ALL
SELECT 1, 'D' FROM DUAL UNION ALL
SELECT 1, 'E' FROM DUAL UNION ALL
SELECT 2, 'B' FROM DUAL UNION ALL
SELECT 2, 'C' FROM DUAL UNION ALL
SELECT 2, 'F' FROM DUAL UNION ALL
SELECT 2, 'G' FROM DUAL UNION ALL
SELECT 3, 'A' FROM DUAL UNION ALL
SELECT 3, 'B' FROM DUAL UNION ALL
SELECT 3, 'C' FROM DUAL UNION ALL
SELECT 3, 'D' FROM DUAL UNION ALL
SELECT 4, 'I' FROM DUAL UNION ALL
SELECT 4, 'J' FROM DUAL UNION ALL
SELECT 4, 'K' FROM DUAL UNION ALL
SELECT 4, 'L' FROM DUAL;
输出:
用户 工作 1,2,3 A,B,C,D,E,F,G 4 我,J,K,L
db<>在这里摆弄
推荐阅读
- r - 写日志闪亮
- sql - 我正在寻找一种方法来获取不同的特定列,选择所有列
- python - 从保存为不同大小的numpy数组的XYZ数据中绘制seaborn热图
- circleci - 将环境变量传递给 CircleCI 中的 node.js 进程
- javascript - 如何使用 lodash 检查两个对象的值是否相同
- python - 在 python 列表中查找 alpha
- android - 如何将 MediatorLiveData 与抽象源一起使用
- javascript - laravel foreach 选择选项和必需
- android-studio - 如何在 android 中测试 Google Play 计费订阅(非应用内购买)
- bison - 野牛匹配模式的顺序是什么?