Laravel 使用查询生成器进行嵌套连接查询

Posted

技术标签:

【中文标题】Laravel 使用查询生成器进行嵌套连接查询【英文标题】:Laravel nested join queries with query builder 【发布时间】:2016-11-16 19:25:37 【问题描述】:

这是一个搜索功能,可返回每个成员最近注册的年份。

我通过 DB::raw() 调用得到了它。但无法让它与查询生成器一起使用。

工作代码:

$query = DB::table('membership as m');
$query->join(
    DB::raw(
        '(SELECT my.*
        FROM membership_years my
        INNER JOIN (
            SELECT member_id,MAX(membership_year) AS max_my
            FROM membership_years
            GROUP BY member_id
        ) my2
        ON my.member_id = my2.member_id
        AND my.membership_year = my2.max_my
        ) my'
    )
,'m.id','=','my.member_id');

我对查询构建器代码的尝试:

$query = DB::table('membership as m');
$query->join('membership_years as my',
  function($j1)
    $j1->join('membership_years as my2',
      function($j2)
        $j2->where('my.membership_year','=','MAX(my2.membership_year)')
        ->on('my.member_id','=','my2.member_id');
      
    )->on('m.id','=','my.member_id');
  
);

产生的错误是:

调用未定义的方法 Illuminate\Database\Query\JoinClause::join()

我不确定这是否是因为 $j2 不再有权访问 join 方法?

原始 MySQL 查询:

SELECT my.membership_year,m.*
FROM membership AS m 
INNER JOIN
    (
        SELECT my1.* 
        FROM membership_years my1 
        INNER JOIN 
        (
            SELECT member_id,MAX(membership_year) AS max_my 
            FROM membership_years 
            GROUP BY member_id
        ) my2
        ON my1.member_id = my2.member_id
        AND my1.membership_year = my2.max_my
    ) my
ON m.id = my.member_id
ORDER BY m.id ASC

【问题讨论】:

【参考方案1】:

方式1.你可以用builder写部分查询:

    $query = DB::table('membership as m')
        ->select('my.membership_year', 'm.*')
        ->join(DB::raw('(
            SELECT my1.* 
            FROM membership_years my1 
            INNER JOIN (
                SELECT member_id, MAX(membership_year) AS max_my 
                FROM membership_years 
                GROUP BY member_id
            ) my2
            ON my1.member_id = my2.member_id
            AND my1.membership_year = my2.max_my
        ) my'),
        'm.id', '=', 'my.member_id')
        ->orderBy('m.id');

方式2。也可以编写子查询并使用toSql()方法:

$sub1 = DB::table('membership_years')
    ->select('member_id', DB::raw('MAX(membership_year) AS max_my'))
    ->groupBy('member_id');

$sub2 = DB::table('membership_years as my1')
    ->select('my1.*')
    ->join(DB::raw('(' . $sub1->toSql() . ') my2'),
            function ($join) 
                $join
                    ->on('my1.member_id', '=', 'my2.member_id')
                    ->on('my1.membership_year', '=', 'my2.max_my');
            );

$query = DB::table('membership as m')
    ->select('my.membership_year', 'm.*')
    ->join(DB::raw('(' . $sub2->toSql() . ') my'), 'm.id', '=', 'my.member_id')
    ->orderBy('m.id');

【讨论】:

展示复杂连接的好例子,在 laravel 5.7 中仍然可以完美运行

以上是关于Laravel 使用查询生成器进行嵌套连接查询的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 查询生成器。返回嵌套结构化数据

使用 Laravel Query Builder 进行复杂的 MySQL 内连接查询

如何使用 Laravel 查询构建器编写嵌套连接?

如何使用 Laravel 的查询构建器执行嵌套连接?

查询生成器 Laravel 左连接

laravel 查询生成器:连接依赖于主要内容