Как сгенерировать первый день недели, последний день недели и номер недели между двумя датами в Oracle

#sql #oracle #date #date-arithmetic

Вопрос:

Я хотел бы вставить в таблицу :

  • первый день недели, начиная с понедельника.
  • последний день недели-воскресенье.
  • номер НЕДЕЛИ => (1-52 или 1-53) в соответствии со стандартом ISO.

Сначала я попытался выбрать первый день, последний день и номер недели для определенной даты, и это работает :

 WITH ranges AS
(
SELECT to_date('29-10-2012', 'dd-MM-yyyy') AS DATE_TEST FROM DUAL
)
SELECT DATE_TEST "DATE",
TO_CHAR( NEXT_DAY( TRUNC(DATE_TEST) , 'SUNDAY' )) "WEEK END DATE",
TO_CHAR(TO_DATE(DATE_TEST,'DD-MON-YYYY'),'WW') 1 "WEEK NUMBER"
FROM ranges ;
 

Но теперь я хотел бы отобразить эти данные между двумя датами, но я получаю результат только для даты начала. кто-нибудь может помочь, пожалуйста.

после, когда все будет хорошо, я вставлю все в таблицу.

Спасибо

 WITH ranges AS(
   select to_date('29-OCT-2012', 'dd-MM-yyyy') START_DATE, 
       to_date('31-DEC-2016', 'dd-MM-yyyy') END_DATE 
from  dual 
)
SELECT START_DATE "DATE",
TO_CHAR( NEXT_DAY( TRUNC(START_DATE) , 'SUNDAY' )) "WEEK END DATE",
TO_CHAR(TO_DATE(START_DATE,'DD-MON-YYYY'),'WW') 1 "WEEK NUMBER"
FROM ranges ;
 

Комментарии:

1. Ваш первый блок кода выдает ошибки. Логика вашего запроса и логика вашего второго блока кода совершенно не совпадают. Ваш запрос явно запрашивает расчеты, основанные на START_DATE . END_DATE не участвует вообще. Возможно, перепишите вопрос заново. Вы действительно спрашиваете, как ranges вывести список всех дат между START_DATE и END_DATE ?

2. @dougp вы правы, копирование/вставка-это моя проблема, извините. я изменил первый блок кода на правильный

Ответ №1:

Формат WW возвращает неделю года (1-53), где неделя 1 начинается в первый день года и продолжается до седьмого дня года, см. Элементы формата даты и времени

Для того, чтобы получить номер недели в соответствии со стандартом ISO-8601, используйте формат IW . Я бы предложил вот так:

 WITH ranges AS(
    SELECT 
        DATE '2012-10-29' START_DATE,
        DATE '2016-12-31' END_DATE 
    FROM dual 
)
SELECT 
    START_DATE, END_DATE,
    TRUNC(START_DATE   7*(LEVEL-1), 'IW') AS Week_Start_Date,
    TRUNC(START_DATE   7*(LEVEL-1), 'IW')   6 AS Week_End_Date,
    TO_CHAR(TRUNC(START_DATE   7*(LEVEL-1)), 'IYYY-"W"IW') WEEK_NUMBER
FROM ranges
CONNECT BY START_DATE   7*(LEVEL-1) <= END_DATE;
 

Комментарии:

1. спасибо, это именно то, что я ищу, и большое спасибо за всю информацию.

Ответ №2:

Похоже, ты ищешь календарь.

Основываясь на вашем RANGES CTE, есть еще один — calendar который использует иерархический запрос для создания всех дат между start_date и end_date . Как только у вас будут все даты, извлеките интересующие вас значения.

 SQL> with
  2  ranges as
  3    (select to_date('29-OCT-2012', 'dd-MM-yyyy') start_date,
  4            to_date('31-DEC-2016', 'dd-MM-yyyy') end_date
  5     from dual
  6    ),
  7  calendar as
  8    (select start_date   level - 1 as datum
  9     from ranges
 10     connect by level <= end_date - start_date   1
 11    )
 12  select
 13    min(datum) start_date,
 14    min(next_day(datum, 'sunday')) week_end_date,
 15    to_char(datum, 'ww') week_number
 16  from calendar
 17  group by to_char(datum, 'yyyy'), to_char(datum, 'ww')
 18  order by 1;

START_DATE WEEK_END_D WE
---------- ---------- --
29-10-2012 04-11-2012 44
04-11-2012 11-11-2012 45
11-11-2012 18-11-2012 46
18-11-2012 25-11-2012 47
25-11-2012 02-12-2012 48
<snip>
09-12-2016 11-12-2016 50
16-12-2016 18-12-2016 51
23-12-2016 25-12-2016 52
30-12-2016 01-01-2017 53

222 rows selected.

SQL>
 

Комментарии:

1. спасибо @littlefoot, это именно то, что я ищу. единственная проблема в том, что номер недели неверен . за первую неделю должно быть 45, а за период с 30-12-2016 по 01-01-2017 должно быть 01. также есть ошибка для START_DATE на первой неделе все хорошо, но вторая неделя и третья… должны начинаться с START_DATE 1, например, вторая неделя должна быть с 05 по 12 ноября по 11 ноября, а на неделе с 09-12-2016 по 11-12-2016 есть только 2 дня, а не неделя как 7 дней или с понедельника по воскресенье

2. Формат WW не возвращает номер недели в соответствии с ISO-8601. Функция NEXT_DAY зависит от текущего сеанса пользователя NLS_DATE_LANGUAGE , который может быть не на английском языке.

Ответ №3:

Как твои дела?

чтобы помочь, я попытался провести некоторые исследования, я нашел эти ссылки.

введите описание ссылки здесь

введите описание ссылки здесь

Я нашел:

ВЫБЕРИТЕ РАУНД((ТРАНК(SYSDATE) — ТРАНК(SYSDATE, ‘ГОД’)) / 7,0) НЕДЕЛЯ, СЛЕДУЮЩИЙ ДЕНЬ(SYSDATE, ‘ВОСКРЕСЕНЬЕ’) — 7 ПЕРВЫЙ ДЕНЬ, СЛЕДУЮЩИЙ ДЕНЬ(SYSDATE, ‘ВОСКРЕСЕНЬЕ’) — 1 ПОСЛЕДНИЙ ДЕНЬ ИЗ ДВУХ

и

выберите to_char(sysdate — to_char(sysdate, ‘d’) 2, ‘yyyymmdd’) первый день_век , to_char(sysdate — to_char(sysdate, ‘d’) 8, ‘yyyymmdd’) последний день_век из двух

и

выберите sysdate КАК сегодня, TRUNC(следующий день(sysdate,»ПОНЕДЕЛЬНИК»)-8) как ДОМИНГО, TRUNC(следующий день(sysdate, «СУББОТА»)) как САБАДО из dual

У меня здесь нет oracle, поэтому я не мог его хорошо протестировать, но он должен решить то, что вам нужно, что угодно, дайте мне знать 🙂

Ответ №4:

Вот способ заставить общее табличное выражение возвращать диапазон дат.

 with ranges (dt) as (
   select to_date('29-OCT-2012', 'dd-MM-yyyy') as dt
   from dual
   
   union all
   select ranges.dt 1
   from ranges
   where ranges.dt < to_date('31-DEC-2016', 'dd-MM-yyyy')
)
 

Затем вы можете использовать это для вычисления других значений.

 SELECT dt "DATE"
, TO_CHAR(NEXT_DAY(TRUNC(dt), 'SUNDAY')) "WEEK END DATE"
, TO_CHAR(TO_DATE(dt,'DD-MON-YYYY'),'WW')   1 "WEEK NUMBER"
, cast(TO_CHAR(dt, 'WW') as int)   
  case when cast(TO_CHAR(dt, 'D') as int) < cast(TO_CHAR(trunc(dt, 'year'), 'D') as int) then 1 else 0 end  WeekNumberInYear

FROM ranges ;
 

Если вы хотите, чтобы все ваши вычисления дат были выполнены одновременно, ознакомьтесь с примером здесь: https://dbfiddle.uk/?rdbms=oracle_18amp;fiddle=35e407af3b5bf711bb7ae53b8cf0e608

Комментарии:

1. Но, основываясь на результатах, я подозреваю, что ваш WEEK END DATE расчет может быть неверным. Например, не должна ли ДАТА ОКОНЧАНИЯ НЕДЕЛИ 04 НОЯБРЯ 2012 года быть 04 НОЯБРЯ 2012 года?

2. Формат WW не возвращает номер недели в соответствии с ISO-8601. Функция NEXT_DAY зависит от текущего сеанса пользователя NLS_DATE_LANGUAGE , который может быть не на английском языке, и функция TO_CHAR(..., 'D') зависит от настроек текущего сеанса пользователя NLS_TERRITORY , которые могут измениться в любое время.

3. Конечно, ОП должен учитывать такие вещи, как я сделал, когда создавал код, который работает на моем рабочем месте.