Laravel中如何获取每个客户的最新账单记录?
问题分析
你当前的查询逻辑存在两个核心问题:
- 使用
groupBy('weekly_billing.customer_id')时,直接选择weekly_billing.*会导致数据库返回分组内任意一条记录的字段值(而非对应max(created_at)的那条),因为非聚合字段未被包含在groupBy中(MySQL严格模式下甚至会直接报错)。 - 仅通过
max(weekly_billing.created_at)获取最新时间,但无法将该时间与对应账单的其他字段关联。
解决方案
以下是几种可行的实现方式,你可以根据自己的数据库版本和需求选择:
方法1:子查询获取最新账单时间后关联
先通过子查询得到每个客户的最新账单创建时间,再关联原表和客户表筛选出对应记录:
$data = DB::table('weekly_billing') ->leftJoin('customers', 'weekly_billing.customer_id', '=', 'customers.id') ->join( DB::raw('(SELECT customer_id, MAX(created_at) AS latest_created FROM weekly_billing GROUP BY customer_id) AS latest_bill'), function ($join) { $join->on('weekly_billing.customer_id', '=', 'latest_bill.customer_id') ->on('weekly_billing.created_at', '=', 'latest_bill.latest_created'); } ) ->select('weekly_billing.*', 'customers.customer_name') ->get();
方法2:使用窗口函数(推荐,需MySQL 8.0+)
利用ROW_NUMBER()窗口函数为每个客户的账单按创建时间倒序编号,然后筛选出编号为1的记录(即最新账单):
$data = DB::table( DB::raw(' SELECT weekly_billing.*, customers.customer_name, ROW_NUMBER() OVER (PARTITION BY weekly_billing.customer_id ORDER BY weekly_billing.created_at DESC) AS rn FROM weekly_billing LEFT JOIN customers ON weekly_billing.customer_id = customers.id ') AS temp ) ->where('rn', 1) ->select('temp.*') ->get();
方法3:Eloquent模型关联方式(若使用模型)
如果你的项目中定义了Customer和WeeklyBilling模型,可以通过关联关系简化查询:
// 在Customer模型中定义关联 public function latestWeeklyBilling() { return $this->hasOne(WeeklyBilling::class)->latest(); } // 查询时直接获取 $data = Customer::with('latestWeeklyBilling')->get();
内容的提问来源于stack exchange,提问作者Mohammed
相关产品推荐
相关产品推荐

