本文介绍如何在 laravel 中通过关联查询,仅统计已“发货”(delivered)状态订单中的商品销量,并获取销量前三的商品列表。
在构建电商后台仪表盘时,常需展示“最畅销商品”,但若直接对 order_details 表聚合统计(如 SUM(quantity)),会忽略订单实际履约状态——例如,待支付、已取消或未发货的订单不应计入真实销售表现。因此,必须将 order_details 与关联的 orders 表进行条件联查,仅纳入 order_status = 'delivered' 的订单数据。
假设你的 OrderDetails 模型已正确定义了与 Order 模型的关联(例如 belongsTo(Order::class, 'order_id')),且 Order 模型中 status 字段存储订单状态(值为 'delivered' 等字符串),则可使用 whereHas() 方法高效完成筛选:
$top_sell_items = OrderDetails::with(['product', 'order']) // 预加载 product 和关联 order(推荐使用更语义化的 'order' 而非 'orders')
->whereHas('order', function ($query) {
$query->where('status', 'delivered');
})
->select('product_id', DB::raw('SUM(quantity) as total_quantity'))
->groupBy('product_id')
->orderBy('total_quantity', 'desc')
->ta
ke(3)
->get();? 关键点说明: whereHas('order', ...) 确保仅选取所属订单状态为 'delivered' 的明细记录; with(['product', 'order']) 支持后续访问 $item->product->name 或 $item->order->created_at 等字段,提升可扩展性; 列别名建议使用 total_quantity 替代 count,避免与 Eloquent 的 count() 方法语义混淆。
// 在 OrderDetails.php 中
public function order()
{
return $this->belongsTo(Order::class, 'order_id');
}CREATE INDEX idx_orders_status_order_id ON orders(status, id);
执行后,$top_sell_items 将是一个包含 3 条 OrderDetails 实例的集合,每条均携带:
你可轻松在 Blade 模板中遍历展示:
@foreach($top_sell_items as $item)
{{ $item->product->name }} — {{ $item->total_quantity }} 件
@endforeach此方案兼顾可读性、性能与 Laravel 最佳实践,是处理跨表状态过滤聚合统计的标准解法。