首页/数据/SQL 速查/WEEK / YEARWEEK 周编号与 mode 参数
函数速查60 条

WEEK / YEARWEEK 周编号与 mode 参数

按周分组统计时的口径控制:MySQL 的 WEEK/YEARWEEK 有 mode 参数决定周起始与计算方式,PostgreSQL 固定 ISO 周。

SQL 速查数据更新于 2026-10-13

WEEK 与 mode 参数是什么

MySQL 的 WEEK(date, mode) 与 YEARWEEK(date, mode) 按 mode 决定周编号规则:mode 同时控制「一周从周日还是周一开始」与「年初不足七天怎么算第 1 周」,可选值分 8 组语义。这是周报统计最容易出错的地方——同一日期在不同 mode 下可能差一周,跨年时更明显。PostgreSQL 用 EXTRACT(WEEK FROM d) 配合 EXTRACT(ISOYEAR FROM d) 取 ISO 周(周一为周首,含 1 月 4 日的那周为第 1 周),或用 date_trunc('week', d) 直接截到周一。

基本信息

MySQLWEEK(date[, mode]),不传 mode 时取 default_week_format 的值
MySQL 年周组合YEARWEEK(date[, mode]),跨年时返回的年份可能属于上一年
PostgreSQLEXTRACT(WEEK FROM d) 与 EXTRACT(ISOYEAR FROM d) 均为 ISO 周口径
PostgreSQL 截断date_trunc('week', d) 固定截到周一
MySQL 取周一DATE_SUB(d, INTERVAL WEEKDAY(d) DAY)

典型使用场景

  • 周报与周环比统计,按周分组汇总订单量
  • 财务周、业务周与自然周口径不同的报表
  • 排班与值班表按周编排
  • 与第三方报表对齐周编号,确认周首日与 ISO 口径
  • 排查跨年时周编号跳变、同一周被拆成两周的问题

MySQL 写法

MySQL 写法
-- 同一日期在不同 mode 下可能落在不同的周
SELECT WEEK('2026-01-01', 0)     AS w_mode0,   # 周日为一周首,年初不足一周算第 0 周
       WEEK('2026-01-01', 1)     AS w_mode1,   # 周一为一周首,含 4 天以上即算第 1 周
       WEEK('2026-01-01', 3)     AS w_mode3,   # ISO 标准周编号
       YEARWEEK('2026-01-01', 3) AS yw;        # 年周组合

-- 按 ISO 周分组统计
SELECT YEARWEEK(created_at, 3) AS yw, COUNT(*) AS cnt
FROM orders
GROUP BY yw
ORDER BY yw;

-- 取某日期所在周的周一,作为周区间起点
SELECT DATE_SUB('2026-10-13', INTERVAL WEEKDAY('2026-10-13') DAY) AS monday;

PostgreSQL 写法

PostgreSQL 写法
-- 按 ISO 周分组:年份取 ISOYEAR,避免跨年被算到错误年份
SELECT EXTRACT(ISOYEAR FROM created_at) AS iso_year,
       EXTRACT(WEEK    FROM created_at) AS iso_week,
       count(*) AS cnt
FROM orders
GROUP BY 1, 2
ORDER BY 1, 2;

-- 直接截到周一,作为周区间起点
SELECT date_trunc('week', created_at)::date AS week_start, count(*)
FROM orders
GROUP BY 1
ORDER BY 1;

用法对照

目标MySQLPostgreSQL
取周编号WEEK(d, mode)EXTRACT(WEEK FROM d)(ISO)
取年周组合YEARWEEK(d, mode)EXTRACT(ISOYEAR…) 与 WEEK 组合
周首日由 mode 决定(0 周日、1 周一)date_trunc('week', d) 固定周一
按周分组GROUP BY YEARWEEK(d, 3)GROUP BY date_trunc('week', d)
MySQL 的 WEEK 在不传 mode 时会读 default_week_format 参数,不同实例的配置可能不一样;写周报 SQL 时必须显式传 mode,否则同一句 SQL 在不同环境的结果可能不同。
跨年周的编号规则必须与业务口径对齐:ISO 周下 1 月 1 日可能属于上一年最后一周,用「日期年份 + 周号」拼出来的键会和自然月报表对不上。
分组前先算周首日更省事:把日期截到周一(MySQL 用 DATE_SUB 减 WEEKDAY,PostgreSQL 用 date_trunc('week', d))后按该列分组,输出天然有序,也避开了周号跨年带来的对齐问题。

易错点

  • 依赖 WEEK 的默认 mode,实例参数不同导致周报口径不一致
  • 跨年时只取日期年份而不用 ISO 年,年末年初的周被算进错误年份
  • 用日期字符串直接分组,同一周的七天被拆成七组
  • 把「周首日是周一还是周日」当小事,与第三方报表差出一天

数据来源与参考

  • MySQL 8.0 Reference Manual · WEEK
  • PostgreSQL Documentation · Date/Time Functions and Operators
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌