MySQL多表JOIN时如何按level排序仅取最小level的关联行
可行性说明
该需求完全可以实现,核心逻辑是先对tbl2按tid分组,提取每个tid对应的最小level值,再通过关联匹配到tbl2中对应的完整行,最终和tbl1关联即可得到预期结果,不会出现一个tbl1行匹配多条tbl2记录的问题。
测试表基础信息
tbl1表:包含id、name、tid三个字段,测试数据为1行:id=1, name='some text', tid=1tbl2表:包含tid、level、related_id三个字段,测试数据为3行:均为tid=1,level分别为1、2、3,对应related_id为4、5、6
具体SQL实现
提供两种常用场景下的写法:
通用兼容写法(支持所有MySQL版本)
先通过子查询聚合出每个tid对应的最小level,再二次关联tbl2拿到对应行的其他字段,最后和tbl1关联:
SELECT t1.id, t1.name, t1.tid, t2.level, t2.related_id FROM tbl1 t1 INNER JOIN ( SELECT tid, MIN(level) AS min_level FROM tbl2 GROUP BY tid ) t2_filter ON t1.tid = t2_filter.tid INNER JOIN tbl2 t2 ON t2_filter.tid = t2.tid AND t2_filter.min_level = t2.level;
MySQL 8.0+ 窗口函数写法(逻辑更简洁)
使用ROW_NUMBER()窗口函数,按关联维度分区后按level升序排序,直接取每个分组排序第一位的记录即可:
SELECT id, name, tid, level, related_id FROM ( SELECT t1.id, t1.name, t1.tid, t2.level, t2.related_id, ROW_NUMBER() OVER (PARTITION BY t1.id ORDER BY t2.level ASC) AS sort_rn FROM tbl1 t1 INNER JOIN tbl2 t2 ON t1.tid = t2.tid ) t_res WHERE sort_rn = 1;
执行结果
上述两种SQL执行后均会返回符合预期的单行数据:
| id | name | tid | level | related_id |
|---|---|---|---|---|
| 1 | some text | 1 | 1 | 4 |
补充说明:如果同一个tid下存在多条level值同为最小值的记录,通用写法会返回所有匹配的最小level行;窗口函数写法如果使用
ROW_NUMBER()会仅返回其中一条,需要保留所有最小level行的话可以将ROW_NUMBER()替换为RANK()。
内容的提问来源于stack exchange,提问作者NoobCode
相关产品推荐
相关产品推荐

