如何编写SQL查询获取各首字母开头的前3条有序结果?
实现按每个首字母取前3条记录的SQL查询
当然可以实现!这种按分组取Top N的需求在SQL里非常常见,下面分不同数据库场景给你对应的解决方案:
支持窗口函数的数据库(MySQL 8.0+、PostgreSQL、SQL Server等)
这类数据库支持ROW_NUMBER()窗口函数,写法简洁直观:
SELECT id, name FROM ( SELECT id, name, -- 按首字母分区,每个分区内按name排序生成行号 ROW_NUMBER() OVER (PARTITION BY LEFT(name, 1) ORDER BY name) AS rn FROM your_table -- 替换成你的实际表名 ) AS ranked_data -- 筛选每个分区内的前3条 WHERE rn <= 3 -- 最终按首字母、行号排序,保证结果顺序符合预期 ORDER BY LEFT(name, 1), rn;
逻辑说明:
- 子查询中用
LEFT(name, 1)提取每条记录的首字母,通过PARTITION BY按首字母分组; ORDER BY name确保每个分组内的记录按名称排序;ROW_NUMBER()为每个分组内的记录生成唯一行号,外层查询筛选行号≤3的记录;- 最终排序保证结果按首字母顺序排列,每个首字母下的记录也按名称排序。
旧版MySQL(5.x及以下,不支持窗口函数)
如果你的MySQL版本较低,可以用用户变量来实现相同逻辑:
SELECT id, name FROM ( SELECT id, name, -- 当首字母和上一条相同时,行号+1,否则重置为1 @row_num := IF(@current_letter = LEFT(name, 1), @row_num + 1, 1) AS rn, -- 更新当前记录的首字母到变量中 @current_letter := LEFT(name, 1) AS current_letter FROM your_table, -- 初始化变量 (SELECT @row_num := 0, @current_letter := '') AS init_vars -- 先按首字母、名称排序,保证变量计算的顺序正确 ORDER BY LEFT(name, 1), name ) AS ranked_data WHERE rn <= 3;
用你的示例数据测试的话,这个查询会返回:
id name
1 Abe
2 Andy
3 Asad
5 Berta
6 Bulma
7 Caan
8 Carl
9 Cesar
11 Dimitri
完全符合你期望的结果~
内容的提问来源于stack exchange,提问作者ndru




