MySQL分组查询:如何按姓氏取最新7条记录(最多9个姓氏)
嘿,针对你的这个MySQL查询需求,我来一步步帮你解决,同时也把分组取指定条数记录的通用方法讲清楚——毕竟你的表有10万+数据,得兼顾效率才行。
满足需求的具体SQL实现
首先假设你的id字段是自增的(最新的记录id值最大),我们可以利用MySQL 8.0+支持的窗口函数来高效实现你的需求:
WITH ranked_records AS ( SELECT id, name, lastname, -- 按姓氏分组,每组内按id降序(最新记录在前)给记录编号 ROW_NUMBER() OVER (PARTITION BY lastname ORDER BY id DESC) AS rn FROM your_table_name -- 替换成你的实际表名 ), limited_surnames AS ( -- 先选出最多9个姓氏,这里按姓氏字母排序,你可以改成按记录数降序等规则 SELECT DISTINCT lastname FROM ranked_records ORDER BY lastname LIMIT 9 ) -- 关联两个结果集,筛选每个姓氏组内前7条最新记录,且只包含那9个姓氏 SELECT rr.id, rr.name, rr.lastname FROM ranked_records rr JOIN limited_surnames ls ON rr.lastname = ls.lastname WHERE rr.rn <= 7 ORDER BY rr.lastname, rr.rn;
代码解释:
ranked_records:用ROW_NUMBER()窗口函数给每个姓氏组的记录编号,rn为1的就是该姓氏最新的记录,以此类推。limited_surnames:先筛选出最多9个目标姓氏,你可以根据需求调整排序逻辑——比如想选记录最多的9个姓氏,把ORDER BY lastname改成ORDER BY (SELECT COUNT(*) FROM your_table_name t WHERE t.lastname = ranked_records.lastname) DESC即可。- 最后关联两个结果集,只保留每个姓氏的前7条最新记录。
MySQL分组查询获取指定数量记录的通用方法
下面分两种场景讲解,优先推荐高效的窗口函数方案:
方法1:窗口函数(MySQL 8.0+,强烈推荐)
窗口函数是处理这类分组取数需求的最优解,只需要扫描一次表,性能极佳,适合大数据量场景。常用的窗口函数有三个,可根据你的需求选择:
ROW_NUMBER():组内每条记录编号唯一,即使排序字段相同也会按顺序编号(适合你需要严格取前N条的场景)RANK():相同排序字段的记录会有相同编号,下一个编号会跳号(比如两个并列第一,下一个就是第三)DENSE_RANK():相同排序字段的记录编号相同,下一个编号不跳号(两个并列第一,下一个是第二)
通用模板:
WITH ranked_data AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY 分组字段 ORDER BY 排序字段 DESC/ASC) AS rn FROM 你的表名 ) SELECT * FROM ranked_data WHERE rn <= N; -- N是每组要取的记录数
优化建议:
给分组字段和排序字段建立联合索引,比如针对你的场景:
CREATE INDEX idx_lastname_id ON your_table_name(lastname, id DESC);
这样窗口函数在分组排序时可以直接利用索引,避免全表扫描,查询速度会快很多。
方法2:子查询关联(兼容低版本MySQL)
如果你的MySQL版本低于8.0,不支持窗口函数,可以用子查询统计组内当前记录的排名,但这种方法性能很差,不建议用于10万+数据的表:
SELECT t1.* FROM your_table_name t1 WHERE ( -- 统计同姓氏中id大于等于当前记录的数量(即当前记录在组内的排名) SELECT COUNT(*) FROM your_table_name t2 WHERE t2.lastname = t1.lastname AND t2.id >= t1.id ) <= 7 ORDER BY t1.lastname, t1.id DESC;
这个方法会对每条记录执行一次子查询,数据量大时会非常慢,所以优先建议升级MySQL版本使用窗口函数方案。
内容的提问来源于stack exchange,提问作者Johny Sharma
相关产品推荐
相关产品推荐

