#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. Конечно, ОП должен учитывать такие вещи, как я сделал, когда создавал код, который работает на моем рабочем месте.