Получение даты для «начала недели» с номерами недели и года на Oracle SQL - PullRequest
0 голосов
/ 08 января 2020

Я работал с запросом, который группирует несколько записей по неделям. Номера недель извлекаются с помощью

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

, после чего используется предложение GROUP BY. «Неделя» всегда начинается в понедельник, и если 1 января не понедельник, неделя 1 начинается с предыдущего понедельника (или, как я понял, в этой строке кода).

Так что если получается следующая таблица (для трех строк примера)

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

Я хотел бы добавить столбец с такой датой, чтобы это было начало недели. Я думал об использовании сгруппированного запроса в качестве подзапроса, а затем просто добавил столбец после, но я не могу точно понять, как сопоставить число недели и года с такой датой.

I пробовал эту строку, чтобы получить дату

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

Но она не выполняется для каждой строки.

Любые идеи, указывающие мне правильное направление, будут оценены.

Ответы [ 2 ]

3 голосов
/ 08 января 2020

ISO-8601 считает первую неделю года первой неделей, на которую приходится большинство дней в этом году. Чтобы иметь большинство своих дней в этом году, он должен содержать как минимум 4 дня недели в этом году и должен содержать 4 января.

Вы можете использовать это для определения начала первого iso -в неделю как:

  • TO_DATE( year, 'YYYY' ) даст 1 января;
  • Затем вы можете добавить 3 дня, чтобы добраться до 4 января; и
  • Используйте TRUNC( date_value, 'IW' ), чтобы получить понедельник 1-й изо-недели года
  • Затем просто добавьте правильное смещение недель к go с 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 

дБ <> скрипка здесь

1 голос
/ 08 января 2020

Согласно ISO-8601 первая неделя - это неделя с 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

...