Laravel 8查询构造器使用DAYNAME函数报错及优化咨询
报错原因
你的代码存在直接触发报错的问题,同时还有隐藏逻辑bug:
- 核心报错原因:Laravel查询构造器的普通
where()方法默认会把第一个入参识别为数据表原生字段名,自动为其添加字段标识符反引号,不会解析内部的SQL函数。传入DAYNAME(created_at)后,框架生成的SQL会把它当做真实存在的字段,拼成`DAYNAME(created_at)` = Monday,自然抛出「列不存在」的错误。如果要在查询中使用SQL函数,需要通过whereRaw()/selectRaw()等方法传入原生SQL表达式。 - 逻辑笔误:
- 周二的查询条件写错,匹配值填的是
Monday,实际查出来的还是周一的数据 - 周六的匹配值
Saturday末尾多打了一个空格,会导致匹配不到对应记录 - 周五的变量名拼写错误(
$firday应为$friday),虽然不直接触发报错,但后续调用很容易引发bug
- 周二的查询条件写错,匹配值填的是
- 性能冗余:
->get()->count()的写法会先把符合条件的所有行全部查询到内存,再在PHP层统计数量,完全可以直接调用->count()让数据库完成聚合计算,减少内存占用和数据传输开销。
优化方案(单次查询完成统计)
不需要重复执行7次查询,通过分组聚合一次就能查完所有数据,性能远高于多次查询,代码维护性也更强:
// 单次查询按星期分组统计记录数 $dayStat = DB::table('watchlists') ->selectRaw('DAYNAME(created_at) as week_day, COUNT(*) as total') ->groupBy('week_day') // 如果需要限定统计范围,比如仅统计当前自然周,解开下面这行注释即可 // ->whereBetween('created_at', [now()->startOfWeek(), now()->endOfWeek()]) ->pluck('total', 'week_day') ->toArray(); // 按周一到周日的顺序组装为Chart.js需要的数组,无数据的日期自动补0 $dayArray = [ $dayStat['Monday'] ?? 0, $dayStat['Tuesday'] ?? 0, $dayStat['Wednesday'] ?? 0, $dayStat['Thursday'] ?? 0, $dayStat['Friday'] ?? 0, $dayStat['Saturday'] ?? 0, $dayStat['Sunday'] ?? 0, ];
稳定性提示:如果你的数据库语言/时区配置不是英文,
DAYNAME()会返回对应语言的星期名称导致匹配失败,这种场景推荐换用不受语言配置影响的WEEKDAY()函数(周一返回0,周日返回6),写法如下:
$dayStat = DB::table('watchlists') ->selectRaw('WEEKDAY(created_at) as week_day, COUNT(*) as total') ->groupBy('week_day') ->pluck('total', 'week_day') ->toArray(); $dayArray = [ $dayStat[0] ?? 0, // 周一 $dayStat[1] ?? 0, // 周二 $dayStat[2] ?? 0, // 周三 $dayStat[3] ?? 0, // 周四 $dayStat[4] ?? 0, // 周五 $dayStat[5] ?? 0, // 周六 $dayStat[6] ?? 0, // 周日 ];
这个写法的优势:
- 仅向数据库发起1次查询,数据量越大性能优势越明显,相比7次查询减少了大量数据库连接、SQL解析、数据传输的开销
- 用
?? 0处理了无数据的日期,既避免数组key不存在的报错,也保证传给Chart.js的数据格式完整,不会出现缺项问题 - 后续如果需要新增时间范围、其他筛选条件,只需要在这一个查询里添加对应where语句即可,维护成本低
内容的提问来源于stack exchange,提问作者JUSTIN CHUA
相关产品推荐
相关产品推荐

