MySQL YEARWEEK() 函数用法与实例

MySQL 中的 YEARWEEK() 函数可以帮助我们从日期中提取年份和周数,便于进行时间相关的数据分析。

发布于

在数据分析和业务报表中,按周统计是常见需求,但当涉及到跨年数据时,简单的周数统计就会遇到难题。MySQL 的 YEARWEEK() 函数完美解决了这个问题,它能够同时返回年份和周数的组合值,确保跨年周数据的准确性。无论是电商平台的周销售分析,还是用户活跃度的周趋势观察,这个函数都能提供可靠的时间维度支持。

YEARWEEK() 函数核心价值

YEARWEEK() 函数是 MySQL 专门为处理跨年周数据设计的实用工具,它将年份和周数合并为一个 6 位或 7 位数字,格式通常为 YYYYWW。与单独的 WEEK() 函数相比,它的最大优势是消除了跨年周数据的歧义,让周统计更加精确可靠。

函数的基本语法结构如下:

YEARWEEK(date, [mode])

其中 date 参数指定要处理的日期,可选的 mode 参数决定周计算的规则,与 WEEK() 函数的模式参数完全一致。

基础使用方法

让我们从最简单的例子开始,了解 YEARWEEK() 的基本行为。

获取当前日期的年周组合:

SELECT YEARWEEK(NOW());

处理特定日期:

SELECT YEARWEEK('2023-12-31');

带模式参数的使用:

SELECT YEARWEEK('2023-01-01', 1);

这些查询会返回类似 202352 这样的 6 位数字,前 4 位是年份,后 2 位是周数。

模式参数详解

YEARWEEK()mode 参数决定了周计算的具体规则,常用的模式包括:

  • 模式 0:周日作为周起始,第一周是本年包含新年的周
  • 模式 1:周一作为周起始,第一周包含 4 天或更多本年天数
  • 模式 2:周日作为周起始,第一周是本年第一个周日所在的周
  • 模式 3:周一作为周起始,第一周包含 4 天或更多本年天数
  • 模式 4:周日作为周起始,第一周是本年包含新年的周
  • 模式 5:周一作为周起始,第一周包含 4 天或更多本年天数
  • 模式 6:周日作为周起始,第一周是本年第一个周日所在的周
  • 模式 7:周一作为周起始,第一周包含 4 天或更多本年天数

模式 1 是最常用的 ISO 标准模式,也是很多国际业务的推荐选择。

实际业务应用案例

YEARWEEK() 在真实业务场景中有着广泛的应用价值。

电商周销售分析

统计每周销售总额:

SELECT
    YEARWEEK(order_date, 1) AS year_week,
    SUM(amount) AS weekly_sales
FROM
    orders
GROUP BY
    year_week
ORDER BY
    year_week;

用户活跃度趋势

分析每周活跃用户数:

SELECT
    YEARWEEK(login_date, 1) AS year_week,
    COUNT(DISTINCT user_id) AS active_users
FROM
    user_logins
GROUP BY
    year_week
ORDER BY
    year_week DESC
LIMIT 10;

数据格式化技巧

为了让 YEARWEEK() 的结果更易读,我们可以进行各种格式化处理。

添加分隔符提高可读性:

SELECT
    CONCAT(
        LEFT(YEARWEEK(order_date, 1), 4),
        '-W',
        RIGHT(YEARWEEK(order_date, 1), 2)
    ) AS formatted_week
FROM
    orders
LIMIT 5;

处理单数周的前导零:

SELECT
    CONCAT(
        YEAR(order_date),
        '-W',
        LPAD(WEEK(order_date, 1), 2, '0')
    ) AS iso_week_format
FROM
    events;

跨年数据处理策略

YEARWEEK() 最大的优势就是能完美处理跨年周数据。

年末周数据分析

正确统计跨年周的数据:

SELECT
    YEARWEEK(sale_date, 1) AS year_week,
    SUM(amount) AS amount
FROM
    sales
WHERE
    YEARWEEK(sale_date, 1) IN (202352, 202301)
GROUP BY
    year_week;

周同比分析

比较不同年份相同周数的数据:

SELECT
    RIGHT(year_week, 2) AS week_number,
    MAX(CASE WHEN LEFT(year_week, 4) = '2022' THEN amount END) AS year_2022,
    MAX(CASE WHEN LEFT(year_week, 4) = '2023' THEN amount END) AS year_2023
FROM (
    SELECT
        YEARWEEK(sale_date, 1) AS year_week,
        SUM(amount) AS amount
    FROM
        sales
    WHERE
        YEARWEEK(sale_date, 1) LIKE '2022%' OR
        YEARWEEK(sale_date, 1) LIKE '2023%'
    GROUP BY
        year_week
) AS weekly_data
GROUP BY
    week_number
ORDER BY
    week_number;

性能优化建议

在大数据量环境下使用 YEARWEEK() 时,需要考虑查询效率。

避免全表扫描

不推荐的写法:

SELECT * FROM large_table WHERE YEARWEEK(date_column, 1) = 202315;

推荐的优化写法:

SELECT * FROM large_table
WHERE date_column BETWEEN
    STR_TO_DATE(CONCAT(2023, ' Monday 1 Week'),
    STR_TO_DATE(CONCAT(2023, ' Sunday 15 Week'));

使用生成列优化

创建预计算的年周列:

ALTER TABLE sales
ADD COLUMN year_week INT
GENERATED ALWAYS AS (YEARWEEK(sale_date, 1)) STORED;

CREATE INDEX idx_year_week ON sales(year_week);

常见问题解决方案

处理不同地区的周起始日

适应不同地区的周起始日需求:

-- 美国地区(周日作为周起始)
SELECT YEARWEEK('2023-07-23', 0);

-- 欧洲地区(周一作为周起始)
SELECT YEARWEEK('2023-07-23', 1);

与其它周函数的对比

比较 YEARWEEK()WEEK() 的结果差异:

SELECT
    date_column,
    WEEK(date_column, 1) AS week_only,
    YEARWEEK(date_column, 1) AS year_week
FROM
    events
WHERE
    MONTH(date_column) = 1;

总结

MySQL 的 YEARWEEK() 函数是处理周数据时不可或缺的工具,特别是对于需要跨年分析的场景。它将年份和周数合并为一个连贯的数值,彻底解决了单纯使用周数可能导致的年份混淆问题。无论是电商销售分析、用户行为研究,还是运营周报生成,这个函数都能提供准确的时间维度支持。在实际应用中,选择正确的模式参数至关重要,模式 1(ISO 标准)通常是国际业务的首选。对于性能敏感的大型应用,考虑使用存储生成列来优化查询效率。掌握 YEARWEEK() 函数的灵活运用,将使您的周数据分析更加专业和高效。