繁体   English   中英

从 Oracle SQL 上的周和年数字获取“一周开始”的日期

[英]Getting a date for "start of the week", from week and year numbers on Oracle SQL

我一直在处理一个按周对许多记录进行分组的查询。 周数由

to_char(reportdate, 'IW') as "Week",   

之后使用GROUP BY子句。 “周”总是从星期一开始,如果 1 月 1 日不是星期一,则第 1 周将从上一个星期一开始(或者我已经理解了这行代码)。

因此,如果获得如下表(对于三个示例行)

Week  Year  Sales  Visits
 32   2017    22     55
 33   2017    30     65
 01   2019    55     103

我想添加一个带有日期的列,以便它是一周的开始。 我正在考虑使用分组查询作为子查询,然后简单地在后面添加一个列,但我无法完全弄清楚如何将周数和年数映射到这样的日期。

我试过这条线来获取日期

trunc(next_day   (trunc(to_date(Yr,'yy'),'yy')  -1,'Mon') + (7*(Wk - 1))    -7)  

但并不是每一行都成立。

任何为我指明正确方向的想法将不胜感激。

ISO-8601 将一年中的第一周计算为该年大部分天数的第一周。 要在该年中拥有大部分天数,那么它必须包含该年内一周中的至少 4 天,并且必须包含 1 月 4 日。

您可以使用它来计算第一个 iso 周的开始时间:

  • TO_DATE( year, 'YYYY' )将给出 1 月 1 日;
  • 然后你可以增加 3 天到 1 月 4 日;
  • 使用TRUNC( date_value, 'IW' )获取一年中第一个等周的星期一
  • 然后只需添加从第 1 周到第 N 周的正确偏移量。

测试数据

CREATE TABLE test_data ( Week, Year, Sales, Visits ) AS
SELECT '32', 2017, 22,  55 FROM DUAL UNION ALL
SELECT '33', 2017, 30,  65 FROM DUAL UNION ALL
SELECT '01', 2019, 55, 103 FROM DUAL;

查询

SELECT t.*,
       TRUNC( TO_DATE( year, 'YYYY' ) + 3, 'IW' ) + 7 * ( week - 1 ) AS week_start
FROM   test_data t

输出

\n周 | 年 | 销售 | 访问 |  WEEK_START\n :--- |  ---: |  ----: |  -----: |  :---------\n 32 |  2017 |  22 |  55 |  07-AUG-17 \n 33 |  2017 |  30 |  65 |  17 年 8 月 14 日 \n 01 |  2019 |  55 |  103 |  18 年 12 月 31 日 \n

db<> 在这里摆弄

根据 ISO-8601,第一周是 1 月 4 日的那一周。 我使用此函数从 ISO-Week 获取日期:

CREATE OR REPLACE FUNCTION ISOWeekDate(WEEK INTEGER, YEAR 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 ISOWeekDate;

请注意,没有年份的周数是不够的,因为 ISO-Year 可能与实际年份不同。 请参阅以下示例:

SELECT to_char(DATE '2019-12-31', 'IYYY-"W"IW') from dual;

TO_CHAR(DATE'2019-12-31','IYYY-"W"IW')
--------------------------------------
2020-W01                              


SELECT ISOWeekDate(1, 2019) from dual;

ISOWEEKDATE(1,2019)
----------------------------
2018-12-31 00:00:00         

当然,当您输入的周/年值可靠时,您可以简单地使用SELECT NEXT_DAY(TO_DATE( yr|| '0104', 'YYYYMMDD' ) - 7, 'MONDAY') + ( wk - 1 ) * 7 AS week_start

暂无
暂无

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

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