【问题标题】:Laravel query builder join after where clauseLaravel 查询生成器在 where 子句之后加入
【发布时间】:2021-08-16 22:16:18
【问题描述】:

我正在使用 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 以获得更好的性能。

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

【问题讨论】:

  • leav_employee_annual_leave_allocations 将受益于INDEX(employee_id, leave_year_id)

标签: php mysql laravel eloquent query-builder


【解决方案1】:

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

这可以通过将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();

使用 Builder 实例

$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
})

【讨论】:

    【解决方案2】:

    或者,您可以将 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)

    【讨论】:

      猜你喜欢
      • 2021-06-26
      • 1970-01-01
      • 1970-01-01
      • 2013-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-07
      相关资源
      最近更新 更多