weekday()返回周一=0至周日=6,适配“周一到周日”分组排序;dayofweek()返回周日=1至周六=7,仅适用于周日优先场景;两者均受时区影响,字符串日期需先用str_to_date()转换。

MySQL中WEEKDAY()和DAYOFWEEK()的区别必须搞清
直接用DAYOFWEEK()分组会得到周日=1、周一=2…周六=7,这和“周一到周日”的自然顺序冲突。真正符合需求的是WEEKDAY():它返回周一=0、周二=1…周日=6,天然适配业务上“以周一为起点”的分组逻辑。
常见错误是查文档看到DAYOFWEEK()返回1~7就直接用,结果分组顺序变成“周日、周一、周二…”,报表一打开就发现数据列错位。
-
WEEKDAY(date):周一=0,周日=6 —— 推荐用于“周一到周日”排序分组 -
DAYOFWEEK(date):周日=1,周六=7 —— 仅在明确需要周日优先时才用 - 两者都受
default_week_format影响极小,但时区设置(如time_zone)会影响结果,务必确认连接会话的时区与业务时区一致
按周一到周日分组并保证排序正确的SQL写法
核心是两步:先用WEEKDAY()生成分组键,再用ORDER BY按该键升序排,才能确保结果从周一(0)到周日(6)依次排列。
示例:统计最近7天每日订单数,按周一到周日对齐
SELECT WEEKDAY(created_at) AS weekday_num, DAYNAME(created_at) AS weekday_name, COUNT(*) AS order_count FROM orders WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL 6 DAY) GROUP BY weekday_num, weekday_name ORDER BY weekday_num;
注意:GROUP BY里必须包含WEEKDAY(created_at)的原始表达式或别名(取决于MySQL版本),不能只靠weekday_name——否则可能因同名(如多个周二)导致合并错误。
遇到STR_TO_DATE()或字符串日期时要先转成DATE类型
如果业务数据里created_at是VARCHAR存的“2024-05-20 14:30:00”,直接套WEEKDAY()会返回NULL,因为函数不接受字符串输入。
- 先用
STR_TO_DATE(created_at, '%Y-%m-%d %H:%i:%s')转为datetime - 再套
WEEKDAY(STR_TO_DATE(...)) - 更稳妥的做法是建生成列或修正表结构,避免每次查询都做转换(性能损耗明显)
错误写法:WEEKDAY('2024-05-20 14:30:00') → 返回NULL;正确写法:WEEKDAY(STR_TO_DATE('2024-05-20 14:30:00', '%Y-%m-%d %H:%i:%s')) → 返回0(周一)
跨周计算时WEEKDAY()不会自动对齐“本周一”,得手动算
比如想查“本周一到周日”的数据,不能只靠WEEKDAY(created_at) = 0来筛周一,而要先算出本周一的日期:
SELECT * FROM orders WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) DAY) AND created_at <p>这段逻辑本质是:用<code>WEEKDAY(CURDATE())</code>拿到今天是本周第几天(0~6),再往前减掉对应天数,就落到本周一。这个值必须参与WHERE条件,否则<code>GROUP BY WEEKDAY(created_at)</code>只是分组,不控制时间范围。</p><p>容易忽略的一点:如果业务要求“固定按自然周(周一至周日)聚合”,且数据横跨多月,记得检查<code>created_at</code>字段是否带有时区偏移(如<code>TIMESTAMP</code> vs <code>DATETIME</code>),否则夏令时切换期可能出现某天重复或遗漏。</p>











