简体   繁体   English

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

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

I have been working with a query that groups a number of records by weeks.我一直在处理一个按周对许多记录进行分组的查询。 The week numbers are extracted by周数由

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

after which a GROUP BY clause is used.之后使用GROUP BY子句。 The "Week" always starts on a Monday and if the 1st January is not a Monday, Week 1 will start from the previous Monday (or so as I've understood this line of code). “周”总是从星期一开始,如果 1 月 1 日不是星期一,则第 1 周将从上一个星期一开始(或者我已经理解了这行代码)。

So if a table such as the following is obtained (for three example rows)因此,如果获得如下表(对于三个示例行)

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

I'd like to add a column with the date such that it is the start of the week.我想添加一个带有日期的列,以便它是一周的开始。 I was thinking of using the grouped query as a sub-query, then simply adding a the column after, but I can't exactly figure out how to map the Week and Year number to such a date.我正在考虑使用分组查询作为子查询,然后简单地在后面添加一个列,但我无法完全弄清楚如何将周数和年数映射到这样的日期。

I've tried this line to obtain the date我试过这条线来获取日期

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

But it has not been holding true for each row.但并不是每一行都成立。

Any ideas to point me in the right direction would be appreciated.任何为我指明正确方向的想法将不胜感激。

ISO-8601 counts the first week of the year as the first week which has the majority of its days in that year. ISO-8601 将一年中的第一周计算为该年大部分天数的第一周。 To have the majority of its days in that year then it must contain at least 4 days of the week within that year and must contain the 4th January.要在该年中拥有大部分天数,那么它必须包含该年内一周中的至少 4 天,并且必须包含 1 月 4 日。

You can use this to work out the start of the first iso-week as:您可以使用它来计算第一个 iso 周的开始时间:

  • TO_DATE( year, 'YYYY' ) will give 1st January; TO_DATE( year, 'YYYY' )将给出 1 月 1 日;
  • Then you can add 3 days to get to the 4th January;然后你可以增加 3 天到 1 月 4 日; and
  • Use TRUNC( date_value, 'IW' ) to get the Monday of the 1st iso-week of the year使用TRUNC( date_value, 'IW' )获取一年中第一个等周的星期一
  • Then just add the correct offset of weeks to go from the 1st to Nth week.然后只需添加从第 1 周到第 N 周的正确偏移量。

Test Data :测试数据

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;

Query :查询

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

Output :输出

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

db<>fiddle here db<> 在这里摆弄

According to ISO-8601 the first week is the week having January 4th.根据 ISO-8601,第一周是 1 月 4 日的那一周。 I use this function to get date from ISO-Week:我使用此函数从 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;

Note, the week number without year is not sufficient, because ISO-Year can be different to actual year.请注意,没有年份的周数是不够的,因为 ISO-Year 可能与实际年份不同。 See these examples:请参阅以下示例:

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         

Of course, when your input week/year values are reliable then you can simply use SELECT NEXT_DAY(TO_DATE( yr|| '0104', 'YYYYMMDD' ) - 7, 'MONDAY') + ( wk - 1 ) * 7 AS week_start当然,当您输入的周/年值可靠时,您可以简单地使用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