从Oracle SQL的星期和年份中获取“一周的开始”日期

时间:2020-01-08 13:08:48

标签: sql oracle date

我一直在使用按星期将许多记录分组的查询。星期数的提取依据是

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)  

但并不是每一行都成立。

任何将我指向正确方向的想法都会受到赞赏。

2 个答案:

答案 0 :(得分:3)

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

您可以使用此方法计算出第一个等周的开始时间,

  • 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

输出

WEEK | YEAR | SALES | VISITS | WEEK_START
:--- | ---: | ----: | -----: | :---------
32   | 2017 |    22 |     55 | 07-AUG-17 
33   | 2017 |    30 |     65 | 14-AUG-17 
01   | 2019 |    55 |    103 | 31-DEC-18 

db <>提琴here

答案 1 :(得分:1)

根据ISO-8601,第一周是1月4日。 我使用此功能从ISO周获取日期:

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