Laravel 7使用whereBetween查询两个月区间数据的问题
问题:Laravel中跨月份区间查询数据异常
我需要查询两个月区间内的数据(例如8月到9月),但当前代码的区间查询逻辑无法得到预期结果,问题出在这段代码:
else if ($bulan1 != "semua" && $bulan2 != "semua") { $query->whereBetween(DB::raw('MONTH(kred_kep_aktf_kompetensi.mulai)'), [$bulan1, $bulan2]); }
以下是完整的函数代码:
public function load_kompetensi(Request $request) { $jenis_kegiatan = $request->input('jenis_kegiatan'); $bulan1 = $request->input('bulan1', 'semua'); $bulan2 = $request->input('bulan2', 'semua'); $tahun = $request->input('tahun', 'semua'); $unit = $request->input('unit', 'semua'); try { $query = DB::connection('database') ->table('kred_kep_aktf_kompetensi') ->join('Karyawan', 'kred_kep_aktf_kompetensi.nid_karyawan', '=', 'Karyawan.NID') ->join('kred_jenis_kegiatan', 'kred_kep_aktf_kompetensi.id_jenis_kegiatan', '=', 'kred_jenis_kegiatan.id') ->join('kred_jenis_peran', 'kred_kep_aktf_kompetensi.id_peran', '=', 'kred_jenis_peran.id') ->select('kred_kep_aktf_kompetensi.*', 'Karyawan.Nama', 'kred_jenis_kegiatan.nama_kegiatan', 'kred_jenis_peran.nama_peran'); if (session('jabatane') == "Pelaksana") { $query->where('kred_kep_aktf_kompetensi.nid_karyawan', session('nidkaryawan')); } else if (session('jabatane') == "Subag/Kanit") { $query->where('kred_kep_aktf_kompetensi.id_unit_kerja', session('unite_id')); } if ($unit != "semua") { $query->where('kred_kep_aktf_kompetensi.id_unit_kerja', $unit); } if ($jenis_kegiatan && $jenis_kegiatan != 'semua') { $query->where('kred_kep_aktf_kompetensi.id_jenis_kegiatan', $jenis_kegiatan); } if ($bulan1 != "semua" && $tahun != "semua") { $query->whereMonth('kred_kep_aktf_kompetensi.mulai', $bulan1) ->whereYear('kred_kep_aktf_kompetensi.mulai', $tahun); } else if ($bulan1 != "semua" && $bulan2 == "semua") { $query->whereMonth('kred_kep_aktf_kompetensi.mulai', $bulan1); } else if ($bulan1 != "semua" && $bulan2 != "semua") { $query->whereBetween(DB::raw('MONTH(kred_kep_aktf_kompetensi.mulai)'), [$bulan1, $bulan2]); } else if ($tahun != "semua") { $query->whereYear('kred_kep_aktf_kompetensi.mulai', $tahun); } $files = $query->orderBy('kred_kep_aktf_kompetensi.id', 'asc')->get(); foreach ($files as $file) { $file->mulai = Carbon::parse($file->mulai)->format('d-m-Y'); $file->akhir = Carbon::parse($file->akhir)->format('d-m-Y'); } } catch (\Throwable $th) { throw $th; } return view("keperawatan.list_aktf_kompetensi_load", ['files' => $files]); }
kred_kep_aktf_kompetensi.mulai字段格式为YYYY-MM-DD HH:MM:SS,示例值:2024-08-09 06:51:30.000。我已测试原生SQL语句:
SELECT * FROM kred_kep_aktf_kompetensi WHERE (MONTH(mulai) BETWEEN 8 AND 9);
该语句能返回预期结果,但将硬编码的8、9替换为请求传入的数字类型参数$bulan1和$bulan2后,仍然无法得到正确结果,寻求解决方法。
解决办法
1. 修正参数类型与区间顺序
首先确保$bulan1和$bulan2是整数类型,且区间顺序正确(避免出现$bulan1=9、$bulan2=8的反向区间):
else if ($bulan1 != "semua" && $bulan2 != "semua") { // 转换为整数类型 $bulan1 = (int)$bulan1; $bulan2 = (int)$bulan2; // 交换顺序确保左值小于等于右值 if ($bulan1 > $bulan2) { [$bulan1, $bulan2] = [$bulan2, $bulan1]; } $query->whereBetween(DB::raw('MONTH(kred_kep_aktf_kompetensi.mulai)'), [$bulan1, $bulan2]); }
2. 补充年份过滤(可选但推荐)
当前逻辑中,月份区间查询未关联年份,会返回所有年份的对应月份数据。如果需要限定在指定年份,需补充年份条件:
else if ($bulan1 != "semua" && $bulan2 != "semua") { $bulan1 = (int)$bulan1; $bulan2 = (int)$bulan2; if ($bulan1 > $bulan2) { [$bulan1, $bulan2] = [$bulan2, $bulan1]; } $query->whereBetween(DB::raw('MONTH(kred_kep_aktf_kompetensi.mulai)'), [$bulan1, $bulan2]); // 如果传入了年份,添加年份过滤 if ($tahun != "semua") { $query->whereYear('kred_kep_aktf_kompetensi.mulai', $tahun); } }
3. 优化为日期范围查询(更高效)
直接基于日期字段做范围查询,既能利用数据库索引提升性能,也能自然解决跨年份问题:
else if ($bulan1 != "semua" && $bulan2 != "semua") { // 确定目标年份,优先使用传入的tahun,否则用当前年份 $targetYear = $tahun != "semua" ? $tahun : Carbon::now()->year; // 构造区间起始和结束日期 $startDate = Carbon::create($targetYear, $bulan1, 1)->startOfMonth(); $endDate = Carbon::create($targetYear, $bulan2, 1)->endOfMonth(); // 直接查询日期范围 $query->whereBetween('kred_kep_aktf_kompetensi.mulai', [$startDate, $endDate]); }
内容的提问来源于stack exchange,提问作者Febryan Akhdani
相关产品推荐
相关产品推荐

