Laravel实现多表头多行每日销售报表问题求助
解决方案
你的问题核心是当前查询仅返回有实际销售记录的卖家-产品组合,且未处理成交叉表结构。要实现需求,需要先生成所有卖家与产品的全量配对,再关联销售数据补0,最后整理为报表格式。
方案一:PHP层补全组合(更直观)
1. 先获取销售数据汇总
// 按卖家+产品分组,计算累计销量 $salesSummary = DB::table('invoice_product') ->join('invoices', 'invoice_product.invoice_id', '=', 'invoices.id') ->whereIn('invoices.seller_id', [1, 2]) ->whereIn('invoice_product.product_id', [1, 2, 3]) ->select( 'invoices.seller_id', 'invoice_product.product_id', DB::raw('SUM(invoice_product.qty) as total_qty') ) ->groupBy('invoices.seller_id', 'invoice_product.product_id') ->get() // 用「卖家ID_产品ID」作为键,方便快速查找 ->keyBy(fn($item) => "{$item->seller_id}_{$item->product_id}");
2. 获取指定的卖家和产品列表
$sellers = Seller::whereIn('id', [1, 2])->get(); $products = Product::whereIn('id', [1, 2, 3])->get();
3. 生成报表结构
$report = []; foreach ($products as $product) { $row = ['product_name' => $product->name]; foreach ($sellers as $seller) { $key = "{$seller->id}_{$product->id}"; // 有销售数据就取汇总值,否则填0 $row[$seller->seller_name] = $salesSummary->has($key) ? $salesSummary[$key]->total_qty : 0; } $report[] = $row; }
方案二:纯SQL生成全量组合(数据库层处理)
通过交叉连接(crossJoin)生成所有卖家-产品的配对,再左连接销售汇总数据,用COALESCE把null转为0:
// 先从数据库拿到所有组合的销量数据(含0) $rawReportData = DB::table('sellers') ->crossJoin('products') ->leftJoin( DB::raw('( SELECT invoices.seller_id, invoice_product.product_id, SUM(invoice_product.qty) as total_qty FROM invoice_product JOIN invoices ON invoice_product.invoice_id = invoices.id WHERE invoices.seller_id IN (1,2) AND invoice_product.product_id IN (1,2,3) GROUP BY invoices.seller_id, invoice_product.product_id ) as sales_summary'), function ($join) { $join->on('sellers.id', '=', 'sales_summary.seller_id') ->on('products.id', '=', 'sales_summary.product_id'); } ) ->whereIn('sellers.id', [1, 2]) ->whereIn('products.id', [1, 2, 3]) ->select( 'products.name as product_name', 'sellers.seller_name', DB::raw('COALESCE(sales_summary.total_qty, 0) as total_qty') ) ->get(); // 转换为交叉表格式 $report = []; $sellerNames = $sellers->pluck('seller_name')->toArray(); foreach ($products as $product) { $row = ['product_name' => $product->name]; foreach ($sellerNames as $sellerName) { $sale = $rawReportData->where('product_name', $product->name) ->where('seller_name', $sellerName) ->first(); $row[$sellerName] = $sale?->total_qty ?? 0; } $report[] = $row; }
最终$report的结构就是你要的:每一行对应一个产品,列是各个卖家的名称,值为对应销量(未销售则为0)。
内容的提问来源于stack exchange,提问作者Talha Bin Ishaq
相关产品推荐
相关产品推荐

