Laravel 6月度销售分数查询异常:列超月末日期且数据错误
Laravel 6 + Datatables 月度销售分数查询问题修正
问题描述
我正在使用Laravel 6框架结合Datatables开发功能,编写了如下代码用于查询指定月份的每日销售分数:
$tglA = Carbon::create($request->tglA)->startOfMonth()->format('Y-m-d'); $tglB = Carbon::create($request->tglB)->lastOfMonth()->format('Y-m-d'); $tglHari = Carbon::create($request->tglA)->lastOfMonth()->format('d'); $period = CarbonPeriod::create($tglA, $tglB)->toArray(); $scoreboard = HistoryPenjualan::select('kodeSales', 'departemenId'); for ($count = 1; $count <= $tglHari; $count++){ $dateFormat = $period[$count-1]->format('Y-m-d'); $scoreboard->selectRaw("SUM(CASE WHEN tgl = '$dateFormat' THEN score ELSE 0 END) AS '$count'"); }; $scoreboard->whereBetween('tgl', [$tglA, $tglB]) ->where('departemenId', $request->departemenId) ->groupBy('departemenId') ->get();
实际运行出现两个问题:
- 返回结果生成了到61的列,远超当月应有的天数
- 部分有数据的日期(如1月30日)分数显示为0
修正方案
1. 统一查询月份,避免跨月
原代码中$tglA和$tglB可能来自不同月份的请求参数,导致$period包含多个月份的日期,同时$tglHari用字符串类型的天数,存在比较逻辑隐患。改为统一使用$request->tglA的月份作为查询范围,用整数类型的当月天数:
$targetDate = Carbon::create($request->tglA); $tglA = $targetDate->startOfMonth()->format('Y-m-d'); $tglB = $targetDate->lastOfMonth()->format('Y-m-d'); $tglHari = $targetDate->daysInMonth; // 直接获取整数类型的当月总天数
2. 修复日期生成逻辑,避免数组越界或错误匹配
原代码依赖$period数组取日期,若跨月会导致数组长度超过当月天数,循环中取到错误日期。改为直接基于目标月份生成每日日期,同时用参数绑定避免SQL注入:
for ($count = 1; $count <= $tglHari; $count++) { // 直接生成当月第count天的日期,无需依赖period数组 $dateFormat = $targetDate->copy()->startOfMonth()->addDays($count - 1)->format('Y-m-d'); // 使用参数绑定替代字符串拼接,避免SQL注入,同时列名改为更规范的day_前缀 $scoreboard->selectRaw("SUM(CASE WHEN tgl = ? THEN score ELSE 0 END) AS day_$count", [$dateFormat]); }
3. 修正分组逻辑,符合SQL规范
原代码select包含kodeSales但仅按departemenId分组,严格SQL模式下会报错,且无法正确按销售代表汇总数据。需将kodeSales加入分组:
$scoreboard->whereBetween('tgl', [$tglA, $tglB]) ->where('departemenId', $request->departemenId) ->groupBy('departemenId', 'kodeSales') // 加入kodeSales确保分组逻辑正确 ->get();
如果只需要部门级别的汇总,直接去掉select中的kodeSales即可。
完整修正代码
$targetDate = Carbon::create($request->tglA); $tglA = $targetDate->startOfMonth()->format('Y-m-d'); $tglB = $targetDate->lastOfMonth()->format('Y-m-d'); $tglHari = $targetDate->daysInMonth; $scoreboard = HistoryPenjualan::select('kodeSales', 'departemenId'); for ($count = 1; $count <= $tglHari; $count++) { $dateFormat = $targetDate->copy()->startOfMonth()->addDays($count - 1)->format('Y-m-d'); $scoreboard->selectRaw("SUM(CASE WHEN tgl = ? THEN score ELSE 0 END) AS day_$count", [$dateFormat]); } $scoreboard->whereBetween('tgl', [$tglA, $tglB]) ->where('departemenId', $request->departemenId) ->groupBy('departemenId', 'kodeSales') ->get();
内容的提问来源于stack exchange,提问作者Retaker
相关产品推荐
相关产品推荐

