Laravel如何获取最后状态为Closed的应用列表(排除非终态)
最后状态为Closed的应用列表
用户提供的数据表结构
表1:applications
| id(pk) | name |
|---|---|
| 1 | naveed |
表2:statuses
| id(pk) | status | application_id(fk) |
|---|---|---|
| 1 | pending | 1 |
| 2 | submitted | 1 |
| 3 | closed | 1 |
| 4 | observation | 1 |
需求说明
获取最后一条状态为Closed的应用列表,仅将最后状态是Closed的应用加入列表,注意:不能将只要有过Closed状态的应用加入列表。
错误实现代码
错误代码1
$applicationsWithClosedStatus = Application::whereHas('statuses', function ($query) { $query->where('status', 'closed'); })->get();
问题:只要应用历史中有过Closed状态就会被筛选,不满足“最后状态为Closed”的要求。
错误代码2
public function status() { return $this->hasOne(Status::class)->latest(); } $applicationsWithLastClosedStatus = Application::whereHas('status', function ($query) { $query->where('status', 'closed'); })->get();
问题:hasOne+latest()定义的关联,在whereHas查询时,Laravel会检查是否存在符合条件的状态记录,而非强制匹配最新的那条,可能导致历史有Closed状态的应用被错误筛选。
正确的Laravel实现方式
方法一:子查询关联(兼容所有Laravel版本)
通过子查询先获取每个应用的最新状态ID,再关联状态表筛选出最新状态为Closed的应用:
$latestStatuses = Status::select('application_id', \DB::raw('MAX(id) as latest_status_id')) ->groupBy('application_id'); $applications = Application::joinSub($latestStatuses, 'latest_statuses', function ($join) { $join->on('applications.id', '=', 'latest_statuses.application_id'); }) ->join('statuses', 'statuses.id', '=', 'latest_statuses.latest_status_id') ->where('statuses.status', 'closed') ->select('applications.*') ->get();
方法二:whereExists子查询
直接通过whereExists判断应用的最新状态是否为Closed:
$applications = Application::whereExists(function ($query) { $query->select(\DB::raw(1)) ->from('statuses as latest_status') ->whereColumn('latest_status.application_id', 'applications.id') ->where('latest_status.status', 'closed') ->whereNotExists(function ($subQuery) { $subQuery->select(\DB::raw(1)) ->from('statuses as newer_status') ->whereColumn('newer_status.application_id', 'latest_status.application_id') ->where('newer_status.id', '>', 'latest_status.id'); }); })->get();
方法三:Eloquent关联(Laravel 8.42+)
在Application模型中定义专门的最新状态关联:
public function latestStatus() { return $this->hasOne(Status::class)->latestOfMany(); }
然后使用whereHas查询:
$applications = Application::whereHas('latestStatus', function ($query) { $query->where('status', 'closed'); })->get();
latestOfMany()是Laravel官方为获取关联最新记录提供的方法,相比latest()更可靠,能确保whereHas匹配的是应用的最后一条状态。
内容的提问来源于stack exchange,提问作者NAVEED SHAHZAD
相关产品推荐
相关产品推荐

