如何关联两个同结构A表与B表并同行展示A表信息且去重
解决双A表关联B表的去重与同行展示问题
嘿,我完全懂你的困扰——把两个结构一模一样的A表通过同一个外键关联到B表,既要把两个A表的信息放在同一行展示,又要干掉那些莫名其妙的重复行,而且你之前尝试的行对比方式性能还拉胯对吧?别慌,给你几个高效的解决方案,比你自己瞎折腾行对比靠谱多了。
先假设咱们的表结构大概是这样(方便你对应自己的表调整):
B表:主键b_id,还有其他业务字段比如b_nameA1、A2表:都有外键b_id关联到B,还有相同的业务字段比如a_data1、a_data2
方案1:用窗口函数提前过滤重复(最灵活)
如果同一个b_id在A1或A2里对应多条记录,你需要指定保留哪一条(比如最新的、ID最大的),那窗口函数就是最优解。它能在关联B表之前就把A表的重复数据过滤掉,避免后续JOIN产生笛卡尔积导致的重复行。
-- 先给每个A表按b_id分组,给每条记录编序号,只取每组第一条 WITH filtered_A1 AS ( SELECT b_id, a_data1, a_data2, -- 按你需要的排序规则来,比如按a_id倒序取最新的 ROW_NUMBER() OVER (PARTITION BY b_id ORDER BY a_id DESC) AS rn FROM A1 ), filtered_A2 AS ( SELECT b_id, a_data1 AS a2_data1, -- 重命名避免字段冲突 a_data2 AS a2_data2, ROW_NUMBER() OVER (PARTITION BY b_id ORDER BY a_id DESC) AS rn FROM A2 ) -- 关联B表和过滤后的A表 SELECT B.b_id, B.b_name, FA1.a_data1, FA1.a_data2, FA2.a2_data1, FA2.a2_data2 FROM B LEFT JOIN filtered_A1 FA1 ON B.b_id = FA1.b_id AND FA1.rn = 1 LEFT JOIN filtered_A2 FA2 ON B.b_id = FA2.b_id AND FA2.rn = 1;
为啥这个方案好?
- 提前过滤A表的重复数据,减少后续JOIN的数据量,性能比事后去重高得多
- 可以精准控制保留哪一条记录,比如把
ORDER BY a_id DESC改成ORDER BY create_time DESC就能取最新创建的那条
方案2:用聚合函数合并行(最简洁)
如果你不在乎同一b_id下A表的多条记录具体保留哪一条,只需要一个有效值(比如随便取最大的、最小的),那用GROUP BY+聚合函数会更简单。
SELECT B.b_id, B.b_name, MAX(A1.a_data1) AS a1_data1, -- 用MAX/MIN都可以,只要能拿到一个有效值 MAX(A1.a_data2) AS a1_data2, MAX(A2.a_data1) AS a2_data1, MAX(A2.a_data2) AS a2_data2 FROM B LEFT JOIN A1 ON B.b_id = A1.b_id LEFT JOIN A2 ON B.b_id = A2.b_id GROUP BY B.b_id, B.b_name; -- 按B表的主键分组,确保一行对应一个B记录
适用场景:
- 同一
b_id下的A表记录业务上是等价的,随便取一个就行 - 不想写复杂的CTE,追求代码简洁
方案3:用DISTINCT暴力去重(最后手段)
如果你的重复行是完全一模一样的(所有字段值都相同),而且前面两种方案不适用,那可以用DISTINCT来强制去重,但这个是下下策——因为数据库需要比对所有结果行的字段,数据量大的时候性能会很差。
SELECT DISTINCT B.b_id, B.b_name, A1.a_data1, A1.a_data2, A2.a_data1, A2.a_data2 FROM B LEFT JOIN A1 ON B.b_id = A1.b_id LEFT JOIN A2 ON B.b_id = A2.b_id;
重要提醒:
- 不管用哪种方案,一定要给
A1.b_id、A2.b_id、B.b_id加索引!索引能让JOIN的速度提升N个档次,比你优化查询逻辑管用多了 - 别再用自定义的行对比逻辑了,数据库的内置函数和JOIN优化器都是经过大厂打磨的,性能甩自定义逻辑几条街
内容的提问来源于stack exchange,提问作者Esteban Rodriguez
相关产品推荐
相关产品推荐

