我一直在使用按星期将许多记录分组的查询。星期数的提取依据是
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)
但并不是每一行都成立。
任何将我指向正确方向的想法都会受到赞赏。
答案 0 :(得分:3)
ISO-8601将一年的第一周视为该年大部分时间的第一周。要拥有该年中大部分的日子,那么它必须包含该年中一周中的至少4天,并且必须包含1月4日。
您可以使用此方法计算出第一个等周的开始时间,
TO_DATE( year, 'YYYY' )
将给1月1日; TRUNC( date_value, 'IW' )
来获取一年中第一个等周的星期一测试数据:
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