【问题标题】:Oracle SQL Get date from year and week numberOracle SQL 从年数和周数中获取日期
【发布时间】:2021-03-19 07:22:40
【问题描述】:

我在 SQL 表的一列中有年份和周数,格式为VERSION_YEAR_WEEKNUMBER 我可以使用SUBSTR 函数来获取YEAR_WEEKNUMBER,但是我需要将其转换为日期,但我不确定如何将周数转换为日期。

理想情况下,日期应该是星期四,但现在我只想将周数转换为该周和年组合中的任何日期。

示例数据只是“VERSION_YEAR_WEEKNUMBER”,例如版本_2020_10。意思是,2020 年,一年中的第 10 周 (ISO)。期望的结果应该是 02-MAR-20 和 08-MAR-20 之间的一个日期

【问题讨论】:

  • 你能发布样本数据和想要的结果吗?
  • 示例数据只是“VERSION_YEAR_WEEKNUMBER”,例如版本_2020_10。意思是,2020 年,一年中的第 10 周 (ISO)
  • 您如何看到这里想要的结果?你能给我们举个例子吗

标签: sql oracle


【解决方案1】:

您可以分别提取年份和周数:

substr(your_column, instr(your_column, '_', -1, 2) + 1, 4)
substr(your_column, instr(your_column, '_', -1, 1) + 1)

然后将年份数字转换为 ISO 年份的第一天:

trunc(to_date(substr(your_column, instr(your_column, '_', -1, 2) + 1, 4), 'YYYY'), 'IYYY')

然后添加周数 - 1 * 7 天以获得该周的星期一,然后添加 3 作为星期四;或添加周数 * 7 天以获得下一周的星期一,然后减去您想要的一周中的星期四:

trunc(to_date(substr(your_column, instr(your_column, '_', -1, 2) + 1, 4), 'YYYY'), 'IYYY')
    + (to_number(substr(your_column, instr(your_column, '_', -1, 1) + 1)) * 7)
    - 4
YOUR_COLUMN     RESULT
--------------- ----------
VERSION_2020_10 2020-03-05
1.2.3_2021_01   2021-01-07
1_2_3_2020_11   2020-03-12
2020_12         2020-03-19
ABC_2020_52     2020-12-24
DEF_2020_53     2020-12-31
GHI_2021_01     2021-01-07
JKL_2021_52     2021-12-30
MNO_2021_53     2022-01-06

db<>fiddle 显示中间步骤,以便您了解发生了什么。

【讨论】:

    【解决方案2】:

    从 ISO 周转换为年份并非易事,因为 ISO 年份可能与实际年份不同。

    例如,根据 ISO-8601,2018-12-31 是 2019 的第 1 周。

    我最终得到了这个功能:

    FUNCTION ISOWeek2Date(YEAR INTEGER, WEEK INTEGER) RETURN DATE DETERMINISTIC IS
        res DATE;
    BEGIN
        IF WEEK > 53 OR WEEK < 1 THEN
            RAISE VALUE_ERROR;      
        END IF;
        res := NEXT_DAY(TO_DATE( YEAR || '0104', 'YYYYMMDD' ) - 7, 'MONDAY') + ( WEEK - 1 ) * 7;
        IF TO_CHAR(res, 'fmIYYY') = YEAR THEN
            RETURN res;
        ELSE
            RAISE VALUE_ERROR;
        END IF;
    END ISOWeek2Date;
    

    但是NEXT_DAY 取决于您会话的日期语言,因此@MT0 的解决方案会更好。逻辑是一样的。

    使用@Alex Poole 提出的正则表达式提取年份和周值

    【讨论】:

      【解决方案3】:

      转换为 ISO 周相对简单,因为 1 月 4 日始终是一年中的第一个 ISO 周。所以:

      • 从当年的 1 月 4 日开始;
      • 将其截回到星期一作为 ISO 周的开始;
      • 加上 3 天,您就有了 ISO 第一周的星期四;然后
      • 添加从第 1 周到所需周的周数。

      像这样:

      SELECT TRUNC( TO_DATE( SUBSTR( value, 9, 4 )||'01-04', 'YYYY-MM-DD' ), 'IW' )
             + INTERVAL '3' DAY
             + INTERVAL '7' DAY * ( SUBSTR( value, 14 ) - 1 )
               AS thursday_of_iso_week
      FROM  table_name
      

      其中,对于样本数据:

      CREATE TABLE table_name ( value ) AS
      SELECT 'VERSION_2020_10' FROM DUAL UNION ALL
      SELECT 'VERSION_2019_1' FROM DUAL
      

      输出:

      | THURSDAY_OF_ISO_WEEK | | :-------------------------------- | | 2020-03-05 00:00:00 | | 2019-01-03 00:00:00 |

      如果值没有固定的字符位置,则使用INSTR 查找下划线:

      SELECT TRUNC( TO_DATE( SUBSTR( value, INSTR( value, '_' ) + 1, 4 )||'01-04', 'YYYY-MM-DD' ), 'IW' )
             + INTERVAL '3' DAY
             + INTERVAL '7' DAY * ( SUBSTR( value, INSTR( value, '_', -1 ) + 1 ) - 1 )
               AS thursday_of_iso_week
      FROM  table_name
      

      与上面的输出相同。

      db小提琴here

      【讨论】:

        【解决方案4】:

        您可以将以下 CTE 加入到您的查询中

        select weekdate, to_char(weekdate, 'IW-yyyy') week_year from (
        SELECT LEVEL weeknr, to_date('2020-01-02', 'yyyy-MM-dd') + numtodsinterval((LEVEL-1)*7, 'day') weekdate
        FROM dual
        CONNECT BY LEVEL <= 53
        );
        

        对于联接,请使用 CTE 的 SUBSTR 和 WEEK_YEAR 的结果。 WEEKDATE 将是日期。此 CTE 生成 2020 年所有星期四的所有周数(1 月 2 日是 2020 年的第一个星期四)。如果您需要更多日期,只需对“LEVEL”使用另一个限制。如果您有大量源数据或非常频繁地查询数据,我建议通过在开头附加“create table ... as”并将其放入表中(一次性完成)并在 WEEK_YEAR 上创建索引(并生成足够的数据,以便您的解决方案可以长时间运行)。

        【讨论】:

        • 有没有办法让我每年都翻滚,所以我在 2021 年、2022 年等都做同样的事情。
        • @M.Phys 是的,如果您将停止条件更改为“CONNECT BY LEVEL
        • @M.Phys 但是,Alex Poole 的解决方案比我的要好。
        • 2020-01-02 是星期六,所以这很可能会返回错误的结果。
        • @WernfriedDomscheit select to_char(to_date('2020-01-02', 'yyyy-MM-dd'), 'DY') from dual; 在我的情况下返回 THU,所以开始日期确实没问题。让我首先想到这个解决方案的真正原因是,to_date 不接受“iw”或“iyyy”作为格式字符(导致ORA-01820: format code cannot appear in date input format 错误)。
        猜你喜欢
        • 2020-12-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-19
        相关资源
        最近更新 更多