多表关联查询:保留重复数据且统计唯一列的正确计数问题
解决关联表查询中保留全量数据+去重计数的问题
嘿,这个场景我太熟悉了!之前做电商订单关联商品的需求时就碰到过一模一样的问题——既要保留主表(tableA)和关联表(tableB)的全量关联数据,又要统计主表不重复的记录数,不能因为一条tableA对应多条tableB数据就重复计数对吧?给你几个实用的解决方案,适配大部分主流SQL数据库(MySQL 8.0+、PostgreSQL、SQL Server等):
方案1:用窗口函数在结果集里直接返回去重计数
如果需要在每一行数据中都带上正确的tableA不重复记录总数,窗口函数是最便捷的方式。它能在不改变原有关联结果的前提下,计算出全局的去重计数:
SELECT A.*, B.*, -- 统计所有不重复的tableA.id,OVER()表示全局范围 COUNT(DISTINCT A.id) OVER () AS unique_a_total FROM tableA A JOIN tableC C ON A.id = C.a_id JOIN tableB B ON C.b_id = B.id;
这样返回的结果里,每一行都会显示正确的tableA不重复记录数,同时完整保留所有A-B的关联数据。
方案2:拆分查询(适合不需要将计数与每行绑定的场景)
如果只需要分别获取全量数据和去重计数,可以拆成两个独立查询,逻辑更清晰:
-- 1. 获取所有A-B关联的全量数据 SELECT A.*, B.* FROM tableA A JOIN tableC C ON A.id = C.a_id JOIN tableB B ON C.b_id = B.id; -- 2. 统计不重复的tableA记录数(只统计有对应B数据的A) SELECT COUNT(DISTINCT A.id) AS unique_a_total FROM tableA A JOIN tableC C ON A.id = C.a_id JOIN tableB B ON C.b_id = B.id;
如果要统计所有tableA记录(包括没有对应B数据的),可以把JOIN改成LEFT JOIN:
SELECT COUNT(DISTINCT A.id) AS unique_a_total FROM tableA A LEFT JOIN tableC C ON A.id = C.a_id LEFT JOIN tableB B ON C.b_id = B.id;
方案3:用CTE合并结果(兼顾灵活性和可读性)
如果需要把全量数据和去重计数合并成一个结果集,又不想用窗口函数,可以用公共表表达式(CTE)先分别计算,再交叉连接:
WITH full_associated_data AS ( -- 先获取全量A-B关联数据 SELECT A.*, B.* FROM tableA A JOIN tableC C ON A.id = C.a_id JOIN tableB B ON C.b_id = B.id ), distinct_a_count AS ( -- 统计不重复的tableA数量 SELECT COUNT(DISTINCT id) AS unique_a_total FROM tableA A WHERE id IN (SELECT a_id FROM tableC) -- 只统计有对应B的A ) -- 将全量数据和计数合并 SELECT f.*, d.unique_a_total FROM full_associated_data f CROSS JOIN distinct_a_count d;
注意事项
- 如果你的数据库版本较低(比如MySQL 5.x)不支持窗口函数,优先用方案2或方案3;
- 当使用LEFT JOIN时,tableA的id不会为NULL,所以COUNT(DISTINCT A.id)依然能正确统计;
- 如果需要按分组统计(比如按A的某个字段分组后,每组内的不重复A数),只需要给窗口函数加上
PARTITION BY A.group_field即可。
内容的提问来源于stack exchange,提问作者dardardardar
相关产品推荐
相关产品推荐

