StarRocks WEEK 函数完全指南:周数计算的 8 种模式与底层实现解析
StarRocks WEEK 函数完全指南周数计算的 8 种模式与底层实现解析【免费下载链接】starrocksThe worlds fastest open query engine for sub-second analytics both on and off the data lakehouse. With the flexibility to support nearly any scenario, StarRocks provides best-in-class performance for multi-dimensional analytics, real-time analytics, and ad-hoc queries. A Linux Foundation project.项目地址: https://gitcode.com/GitHub_Trending/st/starrocksWEEK()是 StarRocks 日期时间函数家族中用于计算给定日期所在周序号的函数行为与 MySQL 的WEEK函数保持一致。在电商大促分析、财务周报、库存周维度聚合等“按周切片”的场景中它是将日期列快速转换为周编号INT的核心工具。读完本文你将掌握WEEK()的完整语法、8 种mode模式的取舍逻辑、边界日期跨年周的判定规则以及该函数在 StarRocks BE 端 C 实现中的底层计算原理从而在 SQL 中正确使用周维度统计避免周一对不上的经典坑。函数定位与版本支持WEEK()返回指定日期在一年中的周序号week number自 StarRocksv2.3起支持。它接受DATETIME或DATE类型的日期参数并可通过可选的mode参数控制“一周从周日还是周一开始”以及“周序号范围是 0–53 还是 1–53”行为完全对齐 MySQL 的WEEK(date[, mode])语义。在实际业务中它与同族的日期函数形成互补关系WEEK()返回周序号本文主题WEEKOFYEAR()等价于WEEK(date, 3)即默认从周一开始、范围 1–53 的 ISO 风格周号YEARWEEK()返回形如YYYYWW的年周组合值DATE_TRUNC(date, week)/DATE_TRUNC(datetime, week)将日期截断到所在周的起始时刻常用于周粒度聚合的分组键。语法与参数说明INT WEEK(DATETIME|DATE date, INT mode)参数明细参数类型必选说明dateDATETIME / DATE是待计算周序号的日期传入时间戳时仅取日期部分参与周计算modeINT否周计算逻辑开关取值 0–7默认0缺省时按 mode 0 处理mode参数同时控制两个维度一周的第一天Sunday 或 Monday以及周序号范围0–53 或 1–53并进一步决定“第 1 周”的判定条件是该年内第一个含周日的周还是该年内第一个含 4 天及以上的周或是第一个含周一的周。完整规则如下表Mode一周的第一天周序号范围第 1 周是第一个满足以下条件的周0Sunday0-53该年内包含一个周日1Monday0-53该年内包含 4 天及以上2Sunday1-53该年内包含一个周日3Monday1-53该年内包含 4 天及以上4Sunday0-53该年内包含 4 天及以上5Monday0-53该年内包含一个周一6Sunday1-53该年内包含 4 天及以上7Monday1-53该年内包含一个周一从这张表可以提炼出 8 种模式的三种基因组合周起始日Sunday/Monday、返回值范围0–53/1–53、第 1 周判定含周日 / 含周一 / 含 4 天以上。其中ISO 8601 标准周对应mode 3周一为一周起点范围 1–53第 1 周必须包含该年的 4 天以上即包含该年的第一个周四mode 1与mode 3的区别仅在于是否允许返回 0mode 1 返回 0–53mode 3 返回 1–53这正是WEEKOFYEAR()与WEEK(date, 1)的差异所在。返回值与边界行为返回类型为INT取值范围 0–53具体区间由mode决定当date取值非法如无法解析的日期或输入为空NULL时函数返回NULL跨年日期会因模式不同出现“回退到上一年最后一周”的情况此时返回值可能是 52/53 或 0详见下文示例。实战示例8 种模式对同一日期的结果差异以下示例统一使用日历上的周一2007-01-012007 年 1 月 1 日完整演示不同模式下同一日期的不同周号mode 0返回 0一周从周日开始2007-01-01是周一不属于该年第一个含周日的周的第 1 周因此返回0mysql SELECT WEEK(2007-01-01, 0); ----------------------- | week(2007-01-01, 0) | ----------------------- | 0 | ----------------------- 1 row in set (0.02 sec)mode 1返回 1一周从周一开始2007-01-01恰为周一直接命中第 1 周mysql SELECT WEEK(2007-01-01, 1); ----------------------- | week(2007-01-01, 1) | ----------------------- | 1 | ----------------------- 1 row in set (0.02 sec)mode 2返回 53一周从周日开始但2007-01-01是周一、不是周日由于 mode 2 的范围是 1–53 且不允许返回 0该日期被归属到上一年2006 年的最后一周即第 53 周mysql SELECT WEEK(2007-01-01, 2); ----------------------- | week(2007-01-01, 2) | ----------------------- | 53 | ----------------------- 1 row in set (0.01 sec)这三个示例清晰展示了“0 与 53 其实是同一周在 0–53 / 1–53 两种范围下的不同呈现”2007-01-01属于 2006 年的最后一周在 0–53 模式下记作0表示尚未进入 2007 年第 1 周在 1–53 模式下记作53上一年的最后一周。更多典型日期验证结合源码测试用例time_functions_test.cpp中的数据可以进一步验证各模式的行为日期mode0mode1mode2mode3mode4mode5mode6mode72007-01-01周一01531015212017-05-0118181818181818182020-09-2338393839383839392015-10-11周日4141414141414141上表中 2007-01-01 各 mode 的结果来自本文示例与测试数据推断2017-05-01、2020-09-23、2015-10-11 的 mode 3/2/1/0/5/7/4/6 结果直接取自 time_functions_test.cpp 中的weeks[]数组{1, 18, 39, 41, 49, 18, 5, 36} 分别对应 mode 3,2,1,0,5,7,4,6。可见2015-10-11 是周日8 种模式结果全部一致41说明不落在跨年边界附近时大多数模式结果趋同2020-09-23 在 mode 0/2/4/5 下为 38、在 mode 1/3/6/7 下为 39体现了周一/周日起点对周归属的实质性影响。在 SQL 中的典型用法-- 统计每日销售额并输出所在周序号默认 mode 0 SELECT WEEK(sale_date) AS week_no, SUM(amount) AS total_amount FROM sales GROUP BY WEEK(sale_date) ORDER BY week_no; -- 使用 ISO 标准周周一为一周起点 SELECT WEEK(sale_date, 3) AS iso_week_no, SUM(amount) AS total_amount FROM sales GROUP BY WEEK(sale_date, 3);底层实现从 SQL 到 C 内核WEEK()并非单独的一个 C 函数它在 StarRocks BE 端由week_of_year_with_default_mode缺省 mode与week_of_year_with_mode显式 mode两个向量化函数承载二者定义于 time_functions.cpp并最终统一调用核心计算函数TimeFunctions::compute_week()与模式归一化函数TimeFunctions::week_mode()。1. 模式归一化week_mode()源码 time_functions.cpp 将用户传入的 mode 折叠为三个位标志的组合uint TimeFunctions::week_mode(uint mode) { uint week_format (mode 7); if (!(week_format WEEK_MONDAY_FIRST)) week_format ^ WEEK_FIRST_WEEKDAY; return week_format; }三个位标志定义于 time_functions.h位标志值含义WEEK_MONDAY_FIRST1周一为一周第一天否则为周日WEEK_YEAR2使用“周年”week year语义涉及跨年归属WEEK_FIRST_WEEKDAY4第 1 周判定依赖一周第一天周日/周一是否出现在该年内其中if (!(week_format WEEK_MONDAY_FIRST)) week_format ^ WEEK_FIRST_WEEKDAY;是一条关键变换当一周从周日开始时自动翻转WEEK_FIRST_WEEKDAY位从而把含周日与含周一两种第 1 周判定统一到同一套算法中。2. 周计算核心compute_week()TimeFunctions::compute_week(year, month, day, week_behaviour, *to_year)time_functions.cpp实现了与 MySQL 一致的周号算法核心逻辑包括日序号day number换算将年/月/日换算为自某基准日以来的累计天数daynr并据此计算该日是周几年初边界判断若日期落在 1 月且day 7 - weekday说明该日期位于跨年周内需要根据WEEK_YEAR与WEEK_FIRST_WEEKDAY决定其归属年份——要么归入上一年最后一周周号可能为 52/53 或 0要么仍算作新年第 1 周周号累加以第 1 周为基准用(daynr - 第一周起始日) / 7的偏移量累加得到周号年末边界修正若week_year days 52 * 7说明日期可能落入 53 周区间需再次校验是否真正属于第 53 周输出年份回写通过*to_year输出实际归属的年份可能为前一年供YEARWEEK()等组合函数复用。配套的compute_weekday(long daynr, bool sunday_first_day_of_week)time_functions.cpp负责基于daynr计算星期几sunday_first_day_of_week参数即为周日起始与周一起始的开关。3. 向量化执行与测试验证BE 端通过DEFINE_TIME_UNARY_FN/DEFINE_TIME_BINARY_FN宏将上述实现包装为可直接作用于列Column的向量化函数week_of_year_with_default_mode单参数日期列内部以week_mode(0)调用compute_week对应 SQL 中的WEEK(date)week_of_year_with_mode双参数日期列 mode 列对应WEEK(date, mode)因此 mode 也可以来自表字段而非仅限常量。上述两种入口的对应测试分别位于 time_functions_test.cppweekWithDefaultModeTest与 time_functions_test.cppweekWithModeTest。后者逐行验证了 2007-01-01、2017-05-01、2020-09-23、2015-10-11、2014-12-11、2001-05-03、2005-02-03、2003-09-03 在 mode 3/2/1/0/5/7/4/6 下的周号可作为实现正确性的直接佐证。周边相关函数与选择建议在周维度分析中建议按如下方式选择函数需求推荐写法说明对齐 MySQL 默认行为WEEK(date)等价WEEK(date, 0)周日起始、0–53符合 ISO 8601 标准周WEEK(date, 3)周一起始、1–53财务/跨国业务常用直接取 ISO 周号WEEKOFYEAR(date)等价WEEK(date, 3)需要年周拼接键YEARWEEK(date)返回YYYYWW避免跨年周与年份错位周粒度聚合分组键DATE_TRUNC(date, week)截断到所在周起始日周一 00:00:00需要特别注意不要将WEEK(date, 0)默认的结果直接与 ISO 周号混用。默认模式以周日为起点而大多数周报约定周一为起点两种口径下同一日期可能相差 1 周跨年日期在 1–53 模式下还会回退到 52/53务必结合YEARWEEK()或分组时同时输出年份字段避免2026 年第 0 周这类歧义数据进入报表。总结WEEK(date[, mode])自 v2.3 起可用行为与 MySQLWEEK()完全一致返回INT型周序号非法/空日期返回NULL8 种 mode 由周起始日周日/周一范围0–53/1–53第 1 周判定含周日/含周一/含 4 天以上三个维度组合而成mode3即 ISO 标准周跨年边界日期的行为最为关键同一2007-01-01在不同 mode 下分别返回 0、1、53深刻理解这一点才能避免周统计口径错误实现层面BE 端由week_of_year_with_default_mode/week_of_year_with_mode调用week_mode()与compute_week()完成计算相关逻辑与测试用例见 time_functions.cpp 与 time_functions_test.cpp可供进一步深入研读。【免费下载链接】starrocksThe worlds fastest open query engine for sub-second analytics both on and off the data lakehouse. With the flexibility to support nearly any scenario, StarRocks provides best-in-class performance for multi-dimensional analytics, real-time analytics, and ad-hoc queries. A Linux Foundation project.项目地址: https://gitcode.com/GitHub_Trending/st/starrocks创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考