SQL LEFT JOIN后因多地址产生重复行,如何获取单人行结果?
解决JOIN后返回单条用户记录的方案
针对你的问题,核心是要每个用户仅返回一行,同时筛选出符合指定地址条件的记录,以下是几种实用方案:
方案1:用EXISTS子查询(仅判断用户是否存在符合条件的地址)
如果不需要返回地址信息,只需要确认用户有指定地址,这个方案最高效:
SELECT A.* FROM A WHERE EXISTS ( SELECT 1 FROM B WHERE B.ID = A.ID AND B.address IN ('add1', 'add2') );
原理:通过子查询判断当前用户是否存在符合条件的地址,只要存在就返回A表的这条记录,自然每个用户仅一行。
方案2:聚合函数合并地址(返回用户信息+所有符合条件的地址)
如果需要把用户所有符合条件的地址合并到一行展示,用字符串聚合函数(不同数据库语法略有差异):
MySQL/MariaDB:
SELECT A.ID, A.Name, A.Age, A.Surname, GROUP_CONCAT(DISTINCT B.address SEPARATOR ', ') AS matched_addresses FROM A LEFT JOIN B ON A.ID = B.ID AND B.address IN ('add1', 'add2') GROUP BY A.ID, A.Name, A.Age, A.Surname;
PostgreSQL/SQL Server:
-- PostgreSQL SELECT A.ID, A.Name, A.Age, A.Surname, STRING_AGG(DISTINCT B.address, ', ') AS matched_addresses FROM A LEFT JOIN B ON A.ID = B.ID AND B.address IN ('add1', 'add2') GROUP BY A.ID, A.Name, A.Age, A.Surname; -- SQL Server SELECT A.ID, A.Name, A.Age, A.Surname, STRING_AGG(B.address, ', ') WITHIN GROUP (ORDER BY B.address) AS matched_addresses FROM A LEFT JOIN B ON A.ID = B.ID AND B.address IN ('add1', 'add2') GROUP BY A.ID, A.Name, A.Age, A.Surname;
注意:把地址筛选条件放在ON子句里,而不是WHERE,这样能保留A表中没有符合地址的用户记录。
方案3:窗口函数取单个地址(返回用户信息+一条符合条件的地址)
如果只需要带回任意一条符合条件的地址,用窗口函数给每个用户的地址排序后取第一条:
SELECT ID, Name, Age, Surname, address FROM ( SELECT A.*, B.address, ROW_NUMBER() OVER (PARTITION BY A.ID ORDER BY B.address) AS rn FROM A LEFT JOIN B ON A.ID = B.ID AND B.address IN ('add1', 'add2') ) AS sub_query WHERE rn = 1 OR address IS NULL;
原理:子查询中用PARTITION BY A.ID给每个用户的地址分组编号,外层取编号为1的记录,同时保留没有符合地址的用户(address IS NULL)。
原SQL的问题说明
你原来的SQL把地址筛选放在WHERE子句里,会导致两个问题:
- 过滤掉A表中没有匹配地址的用户(因为LEFT JOIN后B表字段为NULL,
WHERE b.address=xxx会排除这些记录); - 每个符合地址的B表记录都会和A表连接,所以同一用户会返回多行。
内容的提问来源于stack exchange,提问作者Hemant Dhakal
相关产品推荐
相关产品推荐

