Laravel 查询生成器在 where 子句后加入

Laravel query builder join after where clause

我正在使用 laravel 8。我有这个 mysql 命令,我想将其转换为 laravel 查询生成器样式:

select allocation.*, leav_leave_types.leave_type_code 
from (
    select * from leav_employee_annual_leave_allocations 
    where leave_year_id = $year_id and employee_id = $user_id
) as allocation
left join leav_leave_types on (leav_leave_types.id = allocation.leave_type_id)

实际上我想先应用 where 子句,然后执行 left join 以获得更好的性能。

如何将其转换为查询构建器样式?

您的查询中唯一当前不在 documentation 中的是使用子查询作为主要查询 table。

这可以通过将 ClosureBuilder 实例传递给 table()from() 方法来完成。

  • DB::table(closure, alias)
  • DB::table(builder, alias)
  • DB::query()->from(closure, alias)
  • DB::query()->from(builder, alias)

使用闭包:

DB::table(function ($sub) use ($user_id, $year_id) {
        $sub->from('leav_employee_annual_leave_allocations')
            ->where('leave_year', $year_id)
            ->where('employee_id', $user_id);
    }, 'allocation')
    ->select('allocation.*', 'leav_leave_types.leave_type_code')
    ->leftJoin('leav_leave_types', 'leav_leave_types.id', 'allocation.leave_type_id')
    ->get();
DB::query()
    ->select('allocation.*', 'leav_leave_types.leave_type_code')
    ->from(function ($sub) use ($user_id, $year_id) {
        $sub->from('leav_employee_annual_leave_allocations')
            ->where('leave_year', $year_id)
            ->where('employee_id', $user_id);
    }, 'allocation')
    ->leftJoin('leav_leave_types', 'leav_leave_types.id', 'allocation.leave_type_id')
    ->get();

使用生成器实例

$sub = DB::table('leav_employee_annual_leave_allocations') // or DB::query()->from('leav_employee_annual_leave_allocations')
    ->where('leave_year', $year_id)
    ->where('employee_id', $user_id);

DB::table($sub, 'allocation')
    ->select('allocation.*', 'leav_leave_types.leave_type_code')
    ->leftJoin('leav_leave_types', 'leav_leave_types.id', 'allocation.leave_type_id')
    ->get();
// personally my favorite way. I find it very readable.
$sub = DB::table('leav_employee_annual_leave_allocations') // or DB::query()->from('leav_employee_annual_leave_allocations')
    ->where('leave_year', $year_id)
    ->where('employee_id', $user_id);

DB::query()
    ->select('allocation.*', 'leav_leave_types.leave_type_code')
    ->from($sub, 'allocation')
    ->leftJoin('leav_leave_types', 'leav_leave_types.id', 'allocation.leave_type_id')
    ->get();

生成的SQL看起来像这样

select "allocation".*, "leav_leave_types"."leave_type_code" from (
    select * from "leav_employee_annual_leave_allocations"
    where "leave_year" = ? and "employee_id" = ?
) as "allocation"
left join "leav_leave_types" on "leav_leave_types"."id" = "allocation"."leave_type_id"

如果您希望在连接条件周围生成括号,您应该改用以下符号之一。

leftJoin('leav_leave_types', ['leav_leave_types.id' => 'allocation.leave_type_id'])
leftJoin('leav_leave_types', function ($join) {
    $join->on(['leav_leave_types.id' => 'allocation.leave_type_id']);
})
leftJoin('leav_leave_types', function ($join) {
    // will generate a parenthesis if there's more than one condition
    $join->on('leav_leave_types.id', 'allocation.leave_type_id')
         ->on(...) // and condition
         ->orOn(...); // or condition
})

或者,您可以将 SQL 转为

select *, 
       ( SELECT leave_type_code
             FROM leav_leave_types
             WHERE id = allocation.leave_type_id
       ) AS leave_type_code
    FROM leav_employee_annual_leave_allocations AS allocation
    where leave_year_id = $year_id and employee_id = $user_id

(这样效率可能更高。)

无论哪种情况,leav_employee_annual_leave_allocations 都会受益于 INDEX(employee_id, leave_year_id)