如何实现带LIMIT限制的t_master与t_detail主从表关联查询
查询实现方案
要实现主表关联查询、每个主表记录最多匹配2条明细的需求,核心是先对明细表按关联主表的字段分组,筛选每组前2条记录后再和主表关联,最后生成要求的序号字段即可,以下是不同场景的实现代码:
适用于支持窗口函数的数据库(MySQL 8.0+、PostgreSQL、Oracle、SQL Server等)
这是最简洁高效的实现方式,用ROW_NUMBER()窗口函数完成分组排序打号:
SELECT ROW_NUMBER() OVER(ORDER BY m.ID, d.group_rn) AS `No`, m.ID AS `ID Brand`, d.DetID, d.Model FROM t_master m LEFT JOIN ( SELECT DetID, ParentID, Model, ROW_NUMBER() OVER(PARTITION BY ParentID ORDER BY DetID) AS group_rn FROM t_detail ) d ON m.ID = d.ParentID AND d.group_rn <= 2;
- 子查询逻辑:按关联字段
ParentID分组,每组内按DetID升序排序生成组内序号group_rn,仅保留序号≤2的记录,即每个主表最多匹配2条明细 - 外层逻辑:关联主表后,按主表ID、组内序号排序生成全局连续的
No序号 - 如果需要调整明细的返回优先级,修改子查询里
ORDER BY DetID的排序规则即可,比如要按车型名称倒序取,就改成ORDER BY Model DESC
适用于不支持窗口函数的旧版数据库(如MySQL 5.x)
旧版本数据库没有窗口函数,可以通过关联子查询+用户变量实现同等效果:
SELECT @row_num := @row_num + 1 AS `No`, m.ID AS `ID Brand`, d.DetID, d.Model FROM t_master m LEFT JOIN t_detail d ON m.ID = d.ParentID AND ( SELECT COUNT(*) FROM t_detail d2 WHERE d2.ParentID = d.ParentID AND d2.DetID <= d.DetID ) <= 2 CROSS JOIN (SELECT @row_num := 0) t ORDER BY m.ID, d.DetID;
- 关联子查询的作用是统计同一主表ID下,DetID小于等于当前记录的总条数,条数≤2就保留,实现取每组前2条的效果
- 通过用户变量
@row_num生成全局连续序号 - 如果调整明细排序规则,需要同步修改子查询里的比较条件,和排序规则保持一致
补充说明:你提供的结果示例中ID Brand=2的两条记录DetID标注为1、2属于笔误,按照表结构实际返回的DetID应为4、5,对应车型Civic、Jazz,和表中存储数据一致。
内容的提问来源于stack exchange,提问作者methos
相关产品推荐
相关产品推荐

