Laravel中如何查询子模型最新created_at与父模型next_date不匹配的Eloquent模型
解决方案
要实现这个查询需求,核心是先定位每个Subscription关联的最新Saving记录,再将其created_at与父模型的next_date做对比(同时可按需保留无关联子模型的父模型)。以下是两种可行的实现方式:
方式一:使用子查询关联最新记录
通过whereExists子查询锁定每个订阅的最新储蓄记录,再判断日期是否不匹配:
use Illuminate\Support\Facades\DB; $subscriptions = Subscription::whereNotNull('interval') ->where('interval', '!=', 'manual') ->where(function ($query) { // 覆盖两种场景:1. 无关联储蓄记录;2. 最新储蓄的日期与订阅next_date不相等 $query->doesntHave('savings') ->orWhereExists(function ($subQuery) { $subQuery->select(DB::raw(1)) ->from('savings') ->whereColumn('savings.subscription_id', 'subscriptions.id') // 筛选当前订阅的最新储蓄记录 ->whereRaw('savings.created_at = (SELECT MAX(created_at) FROM savings WHERE subscription_id = subscriptions.id)') // 仅比较日期部分(需完整时间对比可去掉DATE()函数) ->whereRaw('DATE(savings.created_at) != DATE(subscriptions.next_date)'); }); }) ->get();
方式二:使用JOIN关联最新记录
通过两次JOIN先关联每个订阅的最新储蓄时间,再匹配对应的完整记录进行对比:
use Illuminate\Support\Facades\DB; $subscriptions = Subscription::whereNotNull('interval') ->where('interval', '!=', 'manual') // 先关联每个订阅的最新储蓄时间 ->leftJoin(DB::raw('(SELECT subscription_id, MAX(created_at) as latest_created FROM savings GROUP BY subscription_id) as latest_savings'), function ($join) { $join->on('subscriptions.id', '=', 'latest_savings.subscription_id'); }) // 再关联对应的最新储蓄记录 ->leftJoin('savings', function ($join) { $join->on('latest_savings.subscription_id', '=', 'savings.subscription_id') ->on('latest_savings.latest_created', '=', 'savings.created_at'); }) ->where(function ($query) { $query->whereNull('savings.id') // 无储蓄记录的情况 ->orWhereRaw('DATE(savings.created_at) != DATE(subscriptions.next_date)'); }) ->select('subscriptions.*') ->distinct() // 避免重复记录 ->get();
原代码问题说明
你之前用whereDoesntHave的思路偏差了——这个方法是筛选没有符合条件子模型的父模型,但你的需求是要找“子模型中最新的那条不符合日期匹配”的父模型,必须先定位到每个父模型对应的最新子记录,才能完成对比判断。
内容的提问来源于stack exchange,提问作者3m1n3nc3
相关产品推荐
相关产品推荐

