如何在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,nameposts->id,title,user_id,created_at,updated_atcomments->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
相关产品推荐
相关产品推荐

