MySQL中WEEKDAY()返回0~6且周一为0,周末应判断为IN (5, 6);SQL Server需SET DATEFIRST 7后用DATEPART(weekday, date) IN (1, 7);跨库可移植方案用MOD或DATEDIFF计算与已知周一的天数差取模。

MySQL用WEEKDAY()判断周末:注意返回值从周一=0开始
MySQL的WEEKDAY()返回0~6,其中0是周一、5是周六、6是周日——所以周末是WEEKDAY(date) IN (5, 6),不是IN (0, 6)。
常见错误是直接套用“周日=0”的惯性思维,结果把周一当天也当成周末。如果想用周日=0的逻辑,该换用DAYOFWEEK()(它返回1=周日、2=周一…7=周六),此时周末是DAYOFWEEK(date) IN (1, 7)。
示例:
SELECT order_date,
CASE WHEN WEEKDAY(order_date) IN (5, 6) THEN 'weekend' ELSE 'weekday' END AS day_type
FROM orders;
SQL Server用DATEPART()需先设好DATEFIRST
DATEPART(weekday, date)的返回值依赖服务器或会话级的DATEFIRST设置:DATEFIRST 7表示周日为第1天(默认),此时周末是DATEPART(weekday, date) IN (1, 7);若DATEFIRST 1(周一为第1天),则周末变成IN (6, 7)。
不显式指定DATEFIRST容易在不同环境跑出不一致结果。稳妥做法是查询开头加一句:
SET DATEFIRST 7;
SELECT order_date,
CASE WHEN DATEPART(weekday, order_date) IN (1, 7) THEN 'weekend' ELSE 'weekday' END
FROM orders;
或者绕开DATEFIRST,用DATEPART(dw, date)配合@@DATEFIRST动态计算,但多数场景直接SET DATEFIRST 7更直白。
跨数据库可移植写法:用MOD()和TO_DAYS()(MySQL)或DATEDIFF()(SQL Server)
如果要写一次SQL适配多个数据库,避开函数行为差异,可以转为计算距离某个已知周一的天数差再取模:
- MySQL:
MOD(TO_DAYS(date) - TO_DAYS('2024-01-01'), 7) = 5表示周六(因2024-01-01是周一) - SQL Server:
ABS(DATEDIFF(day, '2024-01-01', date)) % 7 IN (5, 6)
这种写法不依赖本地设置,但可读性差、无法走索引,只适合低频分析查询。生产环境优先用原生函数+显式配置。
WHERE条件中用周末判断时,记得考虑时区和日期字段类型
如果order_date是DATETIME或TIMESTAMP,且存储带有时区信息(如UTC),直接用WEEKDAY()或DATEPART()会按数据库所在时区解释——可能把UTC时间当成本地时间算错周末。
解决方法:
- 确认字段是否已转为业务时区(如
CONVERT_TZ(order_date, '+00:00', 'Asia/Shanghai')) - 或统一存为无时区
DATE类型,避免歧义 - PostgreSQL用户注意:
EXTRACT(dow FROM date)返回0=周日,和MySQLDAYOFWEEK()一致,但和WEEKDAY()相反
最常被忽略的是字段类型隐式转换:比如传入字符串'2024-03-30'没加CAST,某些驱动会按本地时区解析成2024-03-29 16:00:00,导致WEEKDAY()算错一天。










