MySQL用WEEKDAY()判断周末为WEEKDAY(created_at) IN (5,6),PostgreSQL用EXTRACT(ISODOW FROM created_at) IN (6,7),SQL Server需考虑@@DATEFIRST,跨库推荐DATEDIFF取模法。

MySQL 中用 WEEKDAY() 判断是否为周末
MySQL 没有直接的 “是否周末” 函数,但 WEEKDAY() 返回 0~6(周一到周日),所以周末是 WEEKDAY(created_at) IN (5, 6)。注意别用 DAYOFWEEK() —— 它返回 1~7(周日是 1),容易搞反。
实操建议:
-
WEEKDAY()更符合直觉(周一=0),推荐优先使用 - 确保
created_at是DATETIME或TIMESTAMP类型,DATE也行;字符串需先用STR_TO_DATE()转换 - 如果表数据量大,
WEEKDAY(created_at)无法走索引,建议加函数索引(MySQL 8.0+):CREATE INDEX idx_created_weekday ON t1 ((WEEKDAY(created_at)))
PostgreSQL 中用 EXTRACT(ISODOW FROM ...)
PostgreSQL 的 EXTRACT(ISODOW FROM created_at) 返回 ISO 标准的星期几(周一=1,周日=7),因此周末是 EXTRACT(ISODOW FROM created_at) IN (6, 7)。别用 EXTRACT(DOW FROM ...) —— 它按周日=0算,周末是 0 和 6,容易混淆。
实操建议:
- 显式写
ISODOW而非DOW,避免语义歧义 - 函数字段无法直接利用普通 B-tree 索引,可建表达式索引:
CREATE INDEX idx_created_isodow ON t1 (EXTRACT(ISODOW FROM created_at)) - 时区敏感:若
created_at是TIMESTAMP WITHOUT TIME ZONE,计算结果依赖会话timezone设置,建议统一用TIMESTAMP WITH TIME ZONE
SQL Server 中用 DATEPART(WEEKDAY, ...) 并检查 @@DATEFIRST
SQL Server 的 DATEPART(WEEKDAY, created_at) 返回值受 SET DATEFIRST 影响,默认 DATEFIRST = 7(周日为第一天),此时周末是 1 和 7;但若数据库或会话改过 DATEFIRST,结果就不可靠。
实操建议:
- 不要硬写
DATEPART(WEEKDAY, created_at) IN (1, 7),应先确认当前@@DATEFIRST值 - 更稳妥的方式是用
DATEPART(WEEKDAY, created_at) % 7 IN (0, 1)(基于周日=1 的默认设定做模运算归一化) - 或者绕开
WEEKDAY,用DATENAME(WEEKDAY, created_at)判断名称(如'Saturday','Sunday'),但性能较差,不适合大表
通用写法:用日期偏移计算星期六/日(跨数据库兼容)
如果需要在多个数据库间保持逻辑一致,或担心函数行为差异,可以用「离某固定基准日的天数差取模」方式。例如以 1900-01-01(周一)为起点,(DATEDIFF(day, '1900-01-01', created_at) % 7) 结果为 5 或 6 即为周末(周六、周日)。
实操建议:
- 该方法不依赖数据库内置星期函数,行为稳定
- 注意不同数据库的日期差函数名不同:
DATEDIFF(SQL Server)、DATE_DIFF(BigQuery)、AGE()配合提取(PostgreSQL)需另写;MySQL 用DATEDIFF(created_at, '1900-01-01') - 基准日必须是周一,否则模 7 后的映射关系全错;1900-01-01 经验证是周一
真正麻烦的不是写哪条语句,而是没意识到各数据库对“周几”的定义根本不同——同一段 SQL 在 MySQL 和 SQL Server 里可能一个返回周六数据,另一个漏掉周日。

















