多表连接冗余行问题求助:父表关联两子表结果行膨胀
解决父表关联多子表产生笛卡尔积的冗余行问题
问题核心
当父表同时左连接两个共享同一父ID的子表时,两个子表的记录会形成笛卡尔积,导致结果行数爆炸。需求是让父表记录对应同序号的子表记录,同时保留无任务/审核的父表行,且不使用聚合或逗号分隔的方式。
解决方案:通过行号关联子表
给两个子表分别按parent_id分组生成行号,然后通过「父ID+行号」的组合关联,确保同序号的子记录配对,彻底避免笛卡尔积。
具体SQL语句
SELECT op.id AS parent_id, op.name AS parent_name, ct.id AS task_id, ct.name AS task_name, cr.id AS review_id, cr.name AS review_name FROM parent_operations_table op LEFT JOIN ( -- 给任务表按父ID分组生成行号,按子表ID排序保证序号稳定 SELECT id, name, parent_id, ROW_NUMBER() OVER (PARTITION BY parent_id ORDER BY id) AS row_num FROM child_task_table ) ct ON op.id = ct.parent_id LEFT JOIN ( -- 给审核表按父ID分组生成行号,排序规则与任务表保持一致 SELECT id, name, parent_id, ROW_NUMBER() OVER (PARTITION BY parent_id ORDER BY id) AS row_num FROM child_review_table ) cr ON op.id = cr.parent_id AND ct.row_num = cr.row_num;
方案说明
- 行号生成逻辑:用
ROW_NUMBER()窗口函数按parent_id分组,按子表自身的id排序生成唯一行号,确保每个父ID下的子记录有固定的序号对应关系。 - 关联规则:两个子表不仅通过
parent_id关联父表,还通过row_num匹配同序号的记录,从根源上切断笛卡尔积的产生。 - 保留左连接特性:即使某个父ID下只有任务没有审核、或只有审核没有任务,对应字段会显示
NULL,完全满足保留无任务/审核父表记录的要求。 - 适配不对称子表行数:如果某个父ID下任务数和审核数不一致(比如3个任务、2个审核),多余的任务行对应的审核字段会是
NULL,反之亦然,不会丢失任何子记录。
验证结果
针对你的测试数据:
- parent_operations_table有(1, Operation_101)、(2, Operation_102)
- child_task_table有2条parent_id=1的记录
- child_review_table有2条parent_id=1的记录
运行上述SQL后会得到:
| parent_id | parent_name | task_id | task_name | review_id | review_name |
|---|---|---|---|---|---|
| 1 | Operation_101 | 1 | ... | 1 | ... |
| 1 | Operation_101 | 2 | ... | 2 | ... |
| 2 | Operation_102 | NULL | NULL | NULL | NULL |
完全符合期望,无冗余行。
内容的提问来源于stack exchange,提问作者Someshwar Roychowdhury
相关产品推荐
相关产品推荐

