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

如何在Laravel Eloquent中结合子查询使用whereColumn实现表关联?

将原生SQL转换为Laravel Eloquent语法

我花了数小时研究后,最终决定在此提问。我正尝试进行表关联,由于某些情况,我必须采用如下所示的查询方式:

select posts.id,
       last_user_comments.created_at
from posts
         left join comments as last_user_comments
                   on (select comments.id
                       from comments
                                join users on users.id = comments.user_id
                                join posts on posts.user_id = users.id
                       where comments.created_at between '2023-01-01' and '2023-01-31'
                       order by comments.created_at desc
                       limit 1) = comments.id;

表结构十分简单:

  • users -> id, name
  • posts -> id, title, user_id, created_at, updated_at
  • comments -> id, comment, post_id, user_id, created_at, updated_at

说明:我不想修改原生SQL,而是希望将其转换为Laravel Eloquent语法。我了解Laravel在JoinClause::on()方法底层使用whereColumn,因此想知道如何编写对应的Eloquent代码。期待各位Laravel工匠的解答。


对应的Eloquent实现代码

这里提供两种写法,完全匹配你的原生SQL逻辑:

写法一:手动处理子查询绑定

use Illuminate\Support\Facades\DB;

// 构建子查询
$subquery = DB::table('comments')
    ->join('users', 'users.id', '=', 'comments.user_id')
    ->join('posts', 'posts.user_id', '=', 'users.id')
    ->whereBetween('comments.created_at', ['2023-01-01', '2023-01-31'])
    ->orderByDesc('comments.created_at')
    ->limit(1)
    ->select('comments.id');

// 主查询关联
$result = DB::table('posts')
    ->leftJoin('comments as last_user_comments', function ($join) use ($subquery) {
        $join->on(DB::raw('(' . $subquery->toSql() . ')'), '=', 'last_user_comments.id')
             ->addBinding($subquery->getBindings());
    })
    ->select('posts.id', 'last_user_comments.created_at')
    ->get();

写法二:利用whereColumn自动处理子查询

这种写法贴合你提到的JoinClause::on()底层逻辑,代码更简洁:

use Illuminate\Support\Facades\DB;

// 构建子查询
$subquery = DB::table('comments')
    ->join('users', 'users.id', '=', 'comments.user_id')
    ->join('posts', 'posts.user_id', '=', 'users.id')
    ->whereBetween('comments.created_at', ['2023-01-01', '2023-01-31'])
    ->orderByDesc('comments.created_at')
    ->limit(1)
    ->select('comments.id');

// 主查询关联
$result = DB::table('posts')
    ->leftJoin('comments as last_user_comments', function ($join) use ($subquery) {
        $join->whereColumn('last_user_comments.id', '=', $subquery);
    })
    ->select('posts.id', 'last_user_comments.created_at')
    ->get();

注意点

你的原生SQL中存在拼写错误:where commnets.created_at应为where comments.created_at,上述Eloquent代码已修正该问题。


内容的提问来源于stack exchange,提问作者Shailesh Matariya

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 12:45:15