You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL中按特殊企业规则从日期转换周数的实现方案

自定义企业周数计算方案(适配DB2、Redshift、SAS)

需求背景

需要在DB2、Redshift(支持DBeaver/SAS查询)中实现符合企业特定规则的日期转周数功能,现有数据库内置周函数均不满足要求,且禁止创建 lookup table。此前团队采用逐年编写大量CASE语句(每年52个WHEN子句)的方式,现需一套无需逐年维护的通用解决方案。

企业周数规则

  • 每周始于周五,结束于下周四
  • 周数上限为52,若计算出第53周则全部并入第52周
  • 第52周始终以当年12月31日为结束日
  • 第1周始终以当年1月1日为起始日
  • 若第1周的天数≤3,则将第2周全部并入第1周,且当年后续所有周数减1

通用实现方案

以下针对不同数据库编写适配的SQL/SAS代码,核心逻辑无需硬编码年份,可自动适配所有年份:

DB2 实现

WITH date_params AS (
    SELECT
        DATE(YEAR(date_col) || '-01-01') AS year_start,
        DATE(YEAR(date_col) || '-12-31') AS year_end,
        date_col
    FROM your_table
),
week1_calc AS (
    SELECT
        year_start,
        year_end,
        date_col,
        -- 计算1月1日所在企业周的自然结束日(周四)
        -- DAYOFWEEK: 周日=1,周一=2...周五=6,周六=7
        (year_start + (11 - DAYOFWEEK(year_start)) % 7 DAYS) AS week1_natural_end,
        -- 计算第1周的天数
        ((11 - DAYOFWEEK(year_start)) % 7) + 1 AS week1_days
    FROM date_params
),
adjusted_week1 AS (
    SELECT
        year_start,
        year_end,
        date_col,
        -- 根据规则5调整第1周结束日
        CASE WHEN week1_days <=3 THEN week1_natural_end + 7 DAYS ELSE week1_natural_end END AS week1_final_end,
        week1_days
    FROM week1_calc
)
SELECT
    date_col,
    CASE
        -- 12月31日所在周强制为52
        WHEN date_col >= year_end - (DAYOFWEEK(year_end) - 5) % 7 DAYS THEN 52
        WHEN date_col <= week1_final_end THEN 1
        ELSE
            MIN(
                INT(DAYS_BETWEEN(date_col, week1_final_end) / 7) + CASE WHEN week1_days <=3 THEN 1 ELSE 2 END,
                51 -- 最后一周已强制为52,此处最多取51
            )
    END AS enterprise_week
FROM adjusted_week1;

Redshift 实现

WITH date_params AS (
    SELECT
        DATE_TRUNC('year', date_col)::DATE AS year_start,
        DATE_TRUNC('year', date_col)::DATE + INTERVAL '1 year' - INTERVAL '1 day' AS year_end,
        date_col
    FROM your_table
),
week1_calc AS (
    SELECT
        year_start,
        year_end,
        date_col,
        -- 计算1月1日所在企业周的自然结束日(周四)
        -- EXTRACT(DOW): 周日=0,周一=1...周五=5,周六=6
        year_start + ((9 - EXTRACT(DOW FROM year_start)) % 7)::INT AS week1_natural_end,
        -- 计算第1周的天数
        ((9 - EXTRACT(DOW FROM year_start)) % 7)::INT + 1 AS week1_days
    FROM date_params
),
adjusted_week1 AS (
    SELECT
        year_start,
        year_end,
        date_col,
        -- 根据规则5调整第1周结束日
        CASE WHEN week1_days <=3 THEN week1_natural_end + 7 ELSE week1_natural_end END AS week1_final_end,
        week1_days
    FROM week1_calc
)
SELECT
    date_col,
    CASE
        -- 12月31日所在周强制为52
        WHEN date_col >= year_end - ((EXTRACT(DOW FROM year_end) - 4) % 7)::INT THEN 52
        WHEN date_col <= week1_final_end THEN 1
        ELSE
            MIN(
                FLOOR(DATEDIFF(day, week1_final_end, date_col) / 7) + CASE WHEN week1_days <=3 THEN 1 ELSE 2 END,
                51
            )
    END AS enterprise_week
FROM adjusted_week1;

SAS 实现

data your_result;
    set your_table;
    /* 计算当年起始和结束日期 */
    year_start = INTNX('year', date_col, 0, 'b');
    year_end = INTNX('year', date_col, 0, 'e');
    
    /* 计算1月1日的星期几,WEEKDAY: 周日=1,周一=2...周五=6,周六=7 */
    dw_year_start = WEEKDAY(year_start);
    /* 计算1月1日所在企业周的自然结束日(周四) */
    week1_natural_end = year_start + (11 - dw_year_start) MOD 7;
    /* 第1周的天数 */
    week1_days = ((11 - dw_year_start) MOD 7) + 1;
    
    /* 根据规则5调整第1周结束日 */
    if week1_days <=3 then week1_final_end = week1_natural_end +7;
    else week1_final_end = week1_natural_end;
    
    /* 计算12月31日所在周的起始日 */
    dw_year_end = WEEKDAY(year_end);
    final_week_start = year_end - ((dw_year_end -5) MOD 7);
    
    /* 计算企业周数 */
    if date_col >= final_week_start then enterprise_week =52;
    else if date_col <= week1_final_end then enterprise_week =1;
    else do;
        days_diff = date_col - week1_final_end;
        base_week = FLOOR(days_diff /7) + (ifn(week1_days <=3, 1, 2));
        enterprise_week = min(base_week, 51);
    end;
run;

方案说明

  • 所有实现均无需硬编码年份,通过动态计算当年的起始/结束日期、第1周参数自动适配任意年份
  • 严格遵循所有企业规则:处理第1周的特殊合并逻辑、强制第52周以12月31日结束、周数上限52
  • 避免了逐年编写CASE语句的维护成本,同时相比大量CASE语句,CTE/数据步的逻辑执行效率更高

内容的提问来源于stack exchange,提问作者RLW

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 01:10:02