MySQL关联查询返回重复记录,求获取唯一结果的解决方案
首先得搞清楚为啥会出现重复记录:你用pid做关联字段,但它并不是两张表的主键——也就是说tbl2里可能存在多个相同的pid值。当执行左连接时,tbl1里的一条记录会和tbl2中所有匹配该pid的记录一一关联,自然就会返回多条重复的tbl1记录。
根据你“获取两张表唯一值”的需求,我给你分场景提供解决方案:
场景1:核心需求是tbl1的唯一记录,兼顾关联的tbl2信息
如果你的重点是拿到所有status='Y'的tbl1唯一记录,同时带上对应的tbl2信息(不管tbl2有多少条匹配记录,只保留关键内容),可以试试这两种方式:
方式1:用DISTINCT去重tbl1字段组合
SELECT DISTINCT l.name, l.id, l.email, l.address, l.pid, l.status, m.domain FROM tbl1 as l LEFT JOIN tbl2 as m on l.pid=m.pid WHERE l.status='Y';
DISTINCT会确保返回的tbl1字段组合是唯一的,但如果同一个tbl1记录对应tbl2的不同domain,还是会返回多条,适合tbl2中一个pid仅对应一个domain的场景。
方式2:按tbl1主键分组,聚合tbl2字段
因为tbl1的id是主键,每个id对应唯一一条记录,所以可以按l.id分组,用聚合函数把tbl2的多条关联信息合并:
SELECT l.*, GROUP_CONCAT(DISTINCT m.domain SEPARATOR ', ') as related_domains FROM tbl1 as l LEFT JOIN tbl2 as m on l.pid=m.pid WHERE l.status='Y' GROUP BY l.id;
GROUP_CONCAT会把同一个pid对应的所有domain用逗号分隔合并,这样每条tbl1记录只会出现一次,同时保留所有关联的domain信息。
场景2:先对tbl2去重,再做连接
如果tbl2里存在重复的pid+domain组合,可以先过滤掉tbl2的重复记录,再和tbl1关联:
SELECT l.*, m.domain FROM tbl1 as l LEFT JOIN ( -- 先获取tbl2中唯一的pid+domain组合 SELECT DISTINCT pid, domain FROM tbl2 ) as m on l.pid=m.pid WHERE l.status='Y';
子查询会先清理tbl2的重复数据,再和tbl1连接,从根源避免tbl1记录被重复关联。
场景3:每个pid只取tbl2中的一条指定记录
如果tbl2中一个pid对应多条不同的domain,但你只想取其中一条(比如最新的、最早的),可以用窗口函数ROW_NUMBER()实现:
SELECT l.*, m.domain FROM tbl1 as l LEFT JOIN ( SELECT pid, domain, -- 按pid分组,给每条记录编号,这里按id升序取最早的一条 ROW_NUMBER() OVER (PARTITION BY pid ORDER BY id) as rn FROM tbl2 ) as m on l.pid=m.pid AND m.rn=1 WHERE l.status='Y';
PARTITION BY pid会把tbl2按pid分组,ORDER BY id决定取哪一条(改成ORDER BY id DESC就能取最新的),rn=1只保留每组的第一条记录,确保tbl1的每条记录只会关联到tbl2的一条记录,不会重复。
内容的提问来源于stack exchange,提问作者prakhar

