MySQL 连接没有笛卡尔积的表
MySQL join tables without cartesian product
我有这样的数据集
group_id
a_id
b_id
c_id
d_id
1
1
无
无
无
1
无
2
无
无
1
无
无
3
无
1
无
无
无
4
1
无
无
无
5
2
11
无
无
无
2
无
12
无
无
2
无
无
13
无
每条记录仅包含 1 个 *_id
,每个 group_id
。我需要为每个 group_id
.
聚合数据集
结果:
group_id
a_id
b_id
c_id
d_id
1
1
2
3
4
1
无
无
无
5
2
11
12
13
无
一些 *_id
可能为空(group_id
的第 3 行)。
并且避免笛卡尔积很重要(在我的示例中,第 2 行仅包含 d_id
= 5,因为前 4 行聚合为一行,并且不再有非聚合的 a_id
、b_id
和 c_id
与 group_id
=1).
是否可以通过 MySQL 连接来做到这一点?
WITH
cte_a AS ( SELECT group_id, a_id, ROW_NUMBER() OVER (PARTITION BY group_id) rn
FROM test
WHERE a_id IS NOT NULL ),
cte_b AS ( SELECT group_id, b_id, ROW_NUMBER() OVER (PARTITION BY group_id) rn
FROM test
WHERE b_id IS NOT NULL ),
cte_c AS ( SELECT group_id, c_id, ROW_NUMBER() OVER (PARTITION BY group_id) rn
FROM test
WHERE c_id IS NOT NULL ),
cte_d AS ( SELECT group_id, d_id, ROW_NUMBER() OVER (PARTITION BY group_id) rn
FROM test
WHERE d_id IS NOT NULL ),
cte_n AS ( SELECT group_id, rn FROM cte_a
UNION
SELECT group_id, rn FROM cte_b
UNION
SELECT group_id, rn FROM cte_c
UNION
SELECT group_id, rn FROM cte_d )
SELECT group_id,
cte_a.a_id,
cte_b.b_id,
cte_c.c_id,
cte_d.d_id
FROM cte_n
LEFT JOIN cte_a USING (group_id, rn)
LEFT JOIN cte_b USING (group_id, rn)
LEFT JOIN cte_c USING (group_id, rn)
LEFT JOIN cte_d USING (group_id, rn)
ORDER BY group_id, rn;
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=87281205ad06780b71b0e90355751e88
PS。如果来自 *_id
的多个值连续不为 NULL,那么这些值可能会出现在不同的输出行中。
我有这样的数据集
group_id | a_id | b_id | c_id | d_id |
---|---|---|---|---|
1 | 1 | 无 | 无 | 无 |
1 | 无 | 2 | 无 | 无 |
1 | 无 | 无 | 3 | 无 |
1 | 无 | 无 | 无 | 4 |
1 | 无 | 无 | 无 | 5 |
2 | 11 | 无 | 无 | 无 |
2 | 无 | 12 | 无 | 无 |
2 | 无 | 无 | 13 | 无 |
每条记录仅包含 1 个 *_id
,每个 group_id
。我需要为每个 group_id
.
结果:
group_id | a_id | b_id | c_id | d_id |
---|---|---|---|---|
1 | 1 | 2 | 3 | 4 |
1 | 无 | 无 | 无 | 5 |
2 | 11 | 12 | 13 | 无 |
一些 *_id
可能为空(group_id
的第 3 行)。
并且避免笛卡尔积很重要(在我的示例中,第 2 行仅包含 d_id
= 5,因为前 4 行聚合为一行,并且不再有非聚合的 a_id
、b_id
和 c_id
与 group_id
=1).
是否可以通过 MySQL 连接来做到这一点?
WITH
cte_a AS ( SELECT group_id, a_id, ROW_NUMBER() OVER (PARTITION BY group_id) rn
FROM test
WHERE a_id IS NOT NULL ),
cte_b AS ( SELECT group_id, b_id, ROW_NUMBER() OVER (PARTITION BY group_id) rn
FROM test
WHERE b_id IS NOT NULL ),
cte_c AS ( SELECT group_id, c_id, ROW_NUMBER() OVER (PARTITION BY group_id) rn
FROM test
WHERE c_id IS NOT NULL ),
cte_d AS ( SELECT group_id, d_id, ROW_NUMBER() OVER (PARTITION BY group_id) rn
FROM test
WHERE d_id IS NOT NULL ),
cte_n AS ( SELECT group_id, rn FROM cte_a
UNION
SELECT group_id, rn FROM cte_b
UNION
SELECT group_id, rn FROM cte_c
UNION
SELECT group_id, rn FROM cte_d )
SELECT group_id,
cte_a.a_id,
cte_b.b_id,
cte_c.c_id,
cte_d.d_id
FROM cte_n
LEFT JOIN cte_a USING (group_id, rn)
LEFT JOIN cte_b USING (group_id, rn)
LEFT JOIN cte_c USING (group_id, rn)
LEFT JOIN cte_d USING (group_id, rn)
ORDER BY group_id, rn;
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=87281205ad06780b71b0e90355751e88
PS。如果来自 *_id
的多个值连续不为 NULL,那么这些值可能会出现在不同的输出行中。