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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 05:32:20