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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 14:45:57