You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MySQL查询:为每种type值获取最多2条记录

刚好之前处理过类似的分组取Top N的需求,给你分享两种靠谱的实现方式,不管是原生SQL还是Laravel Eloquent都能搞定:

原生SQL实现(推荐:窗口函数方案,现代数据库通用)

这是最简洁高效的写法,支持MySQL 8+、PostgreSQL、SQL Server等大部分现代数据库。核心思路是用窗口函数给每个type分组内的行编号,然后筛选出编号≤2的记录:

SELECT id, type, value
FROM (
    SELECT 
        id, 
        type, 
        value,
        -- 按type分组,每组内按id排序并编号
        ROW_NUMBER() OVER (PARTITION BY type ORDER BY id) AS row_num
    FROM example
) AS ranked
WHERE row_num <= 2
-- 按type和id排序,和你期望的结果顺序一致
ORDER BY type, id;

如果需要按其他字段排序(比如value),只需要把ORDER BY id改成ORDER BY value即可,灵活性很高。

兼容老版本数据库的原生SQL写法(比如MySQL 5.x)

如果你的数据库版本不支持窗口函数,就用关联子查询的方式,虽然性能略逊于窗口函数,但小数据量下完全够用:

SELECT e1.id, e1.type, e1.value
FROM example e1
WHERE (
    -- 统计同type下id小于等于当前行的记录数
    SELECT COUNT(*)
    FROM example e2
    WHERE e2.type = e1.type AND e2.id <= e1.id
) <= 2
ORDER BY e1.type, e1.id;
Laravel Eloquent 实现

方案一:用窗口函数(推荐)

直接通过查询构造器实现窗口函数的逻辑,和原生SQL对应:

use Illuminate\Support\Facades\DB;

// 先构建子查询,给每条记录加上分组内的编号
$rankedQuery = DB::table('example')
    ->selectRaw('id, type, value, ROW_NUMBER() OVER (PARTITION BY type ORDER BY id) AS row_num');

// 外层筛选编号≤2的记录,只返回需要的字段
$results = DB::table($rankedQuery, 'ranked')
    ->where('row_num', '<=', 2)
    ->orderBy('type', 'id')
    ->select('id', 'type', 'value')
    ->get();

如果是用Eloquent模型(比如你有Example模型),写法类似:

use App\Models\Example;

$results = Example::query()
    ->fromSub(function ($query) {
        $query->from('examples') // 模型对应的表名,默认是复数
              ->selectRaw('id, type, value, ROW_NUMBER() OVER (PARTITION BY type ORDER BY id) AS row_num');
    }, 'ranked')
    ->where('row_num', '<=', 2)
    ->orderBy('type', 'id')
    ->select('id', 'type', 'value')
    ->get();

方案二:兼容老版本数据库的写法

对应前面的关联子查询,用Eloquent的查询构造器实现:

use App\Models\Example;

$results = Example::query()
    ->where(function ($subQuery) {
        $subQuery->selectRaw('COUNT(*)')
                 ->from('examples as e2')
                 ->whereColumn('e2.type', 'examples.type')
                 ->whereColumn('e2.id', '<=', 'examples.id');
    }, '<=', 2)
    ->orderBy('type', 'id')
    ->get();

这样执行后就能得到你期望的结果:每个type最多返回2条记录,不足2条的返回全部。

内容的提问来源于stack exchange,提问作者I am L

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 09:28:12