You need to enable JavaScript to run this app. 如何在Laravel中不使用原生SQL实现分区查询取各部门薪资Top2
优惠活动
大模型
产品
解决方案
定价
更多

如何在Laravel中不使用原生SQL实现分区查询取各部门薪资Top2

Laravel 实现部门内薪资Top2员工查询的方案

原SQL的核心逻辑为:按部门对员工数据做分区,在分区内按薪资从高到低生成行号,最终筛选行号符合TopN范围的记录,完全可以通过Laravel Eloquent/查询构建器实现,无需编写整段原生SQL。

方案一:Laravel 8+ 原生窗口函数构建(最贴近原SQL逻辑)

Laravel 8.x及以上版本,查询构建器内置了窗口函数的封装能力,可以1:1复现原SQL的执行逻辑:

use App\Models\Employee;

$topPaidStaff = Employee::query()
    ->select(['dept', 'name', 'salary'])
    ->selectSub(function ($query) {
        // 构建row_number窗口函数逻辑
        $query->rowNumber()
            ->partitionBy('dept')
            ->orderByDesc('salary');
    }, 'rn')
    ->where('rn', '<=', 2)
    ->get();

各部分对应关系:

  • rowNumber() 对应SQL原生的row_number()窗口函数
  • partitionBy('dept') 实现按部门划分数据分区的规则
  • orderByDesc('salary') 定义分区内按薪资降序的排序规则
  • where('rn', '<=', 2) 筛选每个部门排序前2的员工

注意:原示例SQL中where T.rn < 2的条件实际只会提取每个部门的第1名员工,和“筛选薪资最高2名”的需求不匹配,需调整为<=2才能覆盖top2范围。

方案二:低版本Laravel兼容实现

如果使用Laravel 7及更早版本,没有内置窗口函数封装,可以通过关联子查询实现同等效果,依然不需要编写整段原生SQL:

use Illuminate\Support\Facades\DB;

$topPaidStaff = DB::table('employees as t1')
    ->select(['t1.dept', 't1.name', 't1.salary'])
    ->whereRaw(
        '(SELECT COUNT(DISTINCT t2.salary) 
         FROM employees as t2 
         WHERE t2.dept = t1.dept AND t2.salary >= t1.salary) <= 2'
    )
    ->orderBy('t1.dept')
    ->orderByDesc('t1.salary')
    ->get();

该逻辑的执行结果和窗口函数方案等价:对每一位员工,统计同部门内薪资不低于他的薪资档位数量,只要数量不超过2,就属于部门内薪资Top2范围。

关联场景下的简化实现

如果已经定义了部门和员工的Eloquent关联,可以直接通过ofMany方法快速实现TopN查询,无需手写子查询逻辑:

// Department 模型内定义关联方法
public function topTwoPaidEmployees()
{
    return $this->hasMany(Employee::class)
        ->ofMany('salary', 'max', function ($query) {
            $query->limit(2);
        });
}

调用时直接预加载关联即可获取每个部门的Top2员工:

$departmentsWithTopStaff = Department::with('topTwoPaidEmployees')->get();

内容的提问来源于stack exchange,提问作者Rashid Abbasi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.05 17:48:00