MySQL YEAR() 函数用法与实例

MySQL 中的 YEAR() 函数可以帮助我们从日期或日期时间值中提取年份。

发布于

在数据分析与报表生成中,按周统计是最常见的需求之一。MySQL 提供的 WEEKOFYEAR() 函数正是专门为这类场景设计的工具,它能准确返回指定日期在一年中的周序号,完全遵循 ISO 8601 国际标准。本文将深入解析这个函数的特性和实际应用,帮助您掌握按周统计数据的核心技巧。

WEEKOFYEAR() 函数核心特性

WEEKOFYEAR() 函数是 MySQL 日期函数家族中的重要成员,它专门用于计算给定日期在当年所处的周数。与普通的 WEEK() 函数不同,它强制采用 ISO 8601 标准定义,具有三个不可变规则:

  • 每周从周一开始
  • 每年的第一周必须包含当年的至少 4 天
  • 返回值范围在 1-53 之间

这种标准化行为消除了因地区差异导致的周数计算不一致问题,特别适合需要国际协作的项目。函数语法极为简洁:

WEEKOFYEAR(date)

只需传入日期或日期时间值,就能获得对应的周序号。

基础应用场景

理解函数的基本行为最直观的方式就是观察不同日期的返回值。

新年周数边界测试:

SELECT
    '2023-01-01' AS date,
    WEEKOFYEAR('2023-01-01') AS week_num;

这个查询可能返回 1 或 52,具体取决于 1 月 1 日是否满足 ISO 第一周的条件(包含至少 4 个当年天数)。

跨年日期对比:

SELECT
    WEEKOFYEAR('2022-12-31') AS last_week_2022,
    WEEKOFYEAR('2023-01-01') AS first_week_2023;

实际案例:计算订单周分布

SELECT
    WEEKOFYEAR(order_date) AS week_number,
    COUNT(*) AS order_count
FROM
    orders
WHERE
    YEAR(order_date) = 2023
GROUP BY
    week_number
ORDER BY
    week_number;

与 WEEK() 函数的深度对比

虽然 WEEKOFYEAR() 可以看作 WEEK(date, 3) 的快捷方式,但理解它们的细微差别很重要。

模式强制一致性:

  • WEEKOFYEAR() 始终相当于 WEEK(date, 3)
  • 无法像 WEEK() 那样通过 mode 参数改变计算规则

返回值范围差异:

SELECT
    WEEK('2023-01-01', 0) AS week_mode0,
    WEEK('2023-01-01', 3) AS week_mode3,
    WEEKOFYEAR('2023-01-01') AS week_of_year;

实际应用选择建议:

  • 需要国际标准化时用 WEEKOFYEAR()
  • 需要自定义周规则时用 WEEK() 配合 mode 参数

高级应用技巧

掌握基础用法后,我们可以解锁更强大的应用方式。

周数补零格式化:

SELECT
    CONCAT(YEAR(NOW()), '-W', LPAD(WEEKOFYEAR(NOW()), 2, '0')) AS iso_week_format;

跨年周数据合并:

SELECT
    CONCAT(YEAR(date), WEEKOFYEAR(date)) AS year_week,
    SUM(amount) AS total
FROM
    transactions
GROUP BY
    year_week;

周进度计算:

SELECT
    (WEEKOFYEAR(CURDATE()) /
    WEEKOFYEAR(CONCAT(YEAR(CURDATE()), '-12-31'))) * 100
AS year_progress_percent;

实际业务案例分析

通过真实业务场景展示函数的实用价值。

零售业销售周报:

SELECT
    WEEKOFYEAR(sale_date) AS week_num,
    SUM(CASE WHEN product_category = '电子' THEN amount ELSE 0 END) AS electronics,
    SUM(CASE WHEN product_category = '服装' THEN amount ELSE 0 END) AS clothing
FROM
    sales
WHERE
    YEAR(sale_date) = 2023
GROUP BY
    week_num
ORDER BY
    week_num;

用户活跃度周趋势:

SELECT
    WEEKOFYEAR(login_date) AS week,
    COUNT(DISTINCT user_id) AS active_users,
    ROUND(COUNT(*)/7, 1) AS daily_avg_logins
FROM
    user_activity
GROUP BY
    week
ORDER BY
    week;

边界情况处理

处理年末周数计算的特殊场景。

跨年周数据衔接:

SELECT
    CONCAT(
        IF(WEEKOFYEAR(date) > 50 AND MONTH(date) = 1, YEAR(date)-1, YEAR(date)),
        'W',
        LPAD(WEEKOFYEAR(date), 2, '0')
    ) AS safe_year_week
FROM
    events;

闰年周数检测:

SELECT
    WEEKOFYEAR('2024-12-31') AS total_weeks_2024;
-- 返回53表示闰年有53周

性能优化建议

大数据量下的高效查询方案。

创建周数预计算列:

ALTER TABLE sales ADD COLUMN week_of_year TINYINT
AS (WEEKOFYEAR(sale_date)) STORED;

CREATE INDEX idx_week ON sales(week_of_year);

分区表按周优化:

CREATE TABLE web_logs (
    log_date DATE,
    -- 其他字段
    PARTITION BY RANGE (WEEKOFYEAR(log_date)) (
        PARTITION p1 VALUES LESS THAN (10),
        PARTITION p2 VALUES LESS THAN (20),
        -- 更多分区...
    )
);

总结

MySQL 的 WEEKOFYEAR() 函数是处理基于周的数据分析时不可或缺的工具,它的标准化输出确保了全球范围内计算的一致性。无论是生成周报表、分析周期性趋势,还是进行时间序列预测,这个函数都能提供准确可靠的周数参考。特别值得注意的是,在涉及跨年日期处理时,结合 YEAR() 函数使用可以避免常见的数据归类错误。对于性能敏感的应用,预先计算并存储周数指标是值得推荐的优化策略。掌握 WEEKOFYEAR() 的灵活运用,能让您的日期数据处理能力提升到一个新的专业水准。