繁体   English   中英

Oracle SQL 从年和周数中获取日期

[英]Oracle SQL Get date from year and week number

我在SUBSTR表中有年份和周YEAR_WEEKNUMBER ,格式为VERSION_YEAR_WEEKNUMBER weeknumber 到日期。

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

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

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

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显示中间步骤,以便您查看发生了什么。

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

例如,根据 ISO-8601,20 18 -12-31 是 20 19的第 1 周。

我最终得到了这个 function:

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取决于您的 session 的日期语言,因此@MT0 的解决方案会更好。 逻辑是一样的。

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

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

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

像这样:

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<> 在这里摆弄

您可以将以下 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 上创建索引(并生成足够的数据,以便您的解决方案可以长时间工作)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM