2016-02-10 2 views
1

У меня есть таблица, которая заполняется информацией один раз в неделю, с датой, когда она заполняется в виде одного столбца в таблице.Расчет за неделю до

Я работаю над запросом, который в основном сравнивает данные с этой недели с данными с прошлой недели исключительно, поэтому мне нужно знать, какая неделя была на прошлой неделе. Это легко сделать следующим образом:

WHERE TO_CHAR(LASTWEEK.DATE_GENERATED, 'IW') = TO_CHAR(SYSDATE, 'IW') -1 
    AND TO_CHAR(LASTWEEK.DATE_GENERATED, 'YY') = TO_CHAR(SYSDATE, 'YY') 

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

Проблема возникает, когда мы находимся в первую неделю года, и мы хотим сравнить ее с прошлой неделей. Таким образом, мы находимся на неделе 1 минус 1, это дает нам 0, но я хочу, чтобы он сравнивался с 54-й неделей с LAST года.

Есть ли способ сделать это?

Я чувствую, что функция TRUNC может работать с этим, но я не уверен, как использовать его в этом сценарии, также имея в виду, что он не должен сравниваться с тем же годом, но в прошлом году.

Заранее благодарен!

+1

Просто быть придирчивым, в прошлом году не было недели 54. Но вы должны использовать IYYY (или, по крайней мере, IY), если вы используете IW, иначе вы можете получить странные результаты. 2016-01-01 - это 1653 с YYIW и 201653 с YYYYIW , но 1553 с IYIW и 201553 с IYYYIW. (И 1601 wi й YYWW и 201601 с YYYYWW, если вы предпочитаете; просто быть последовательным). –

ответ

3

Вы можете сравнить с датой неделю назад, с помощью sysdate - 7, и в сочетании с одним значением:

WHERE TO_CHAR(LASTWEEK.DATE_GENERATED, 'IYYYIW') = TO_CHAR(SYSDATE - 7, 'IYYYIW') 

Обратите внимание, я использую в год модель IYYY, чтобы соответствовать IW один, в противном случае вы» d получите нечетные результаты.

Но поскольку @ditto показывает, что использовать TRUNC с маской формата IW чище. И поскольку @MaxU указал, что усечение исходного столбца предотвратит использование индексов, если у вас нет соответствующего функционального индекса. Вы можете избежать этого, слегка изменив подход Дитто:

WHERE LASTWEEK.DATE_GENERATED >= TRUNC(SYSDATE - 7, 'IW') 
AND LASTWEEK.DATE_GENERATED < TRUNC(SYSDATE, 'IW'); 

В демо:

with lastweek(date_generated) as (
    select sysdate - level from dual connect by level <= 50 
) 
SELECT LASTWEEK.DATE_GENERATED 
FROM LASTWEEK 
WHERE LASTWEEK.DATE_GENERATED >= TRUNC(SYSDATE - 7, 'IW') 
AND LASTWEEK.DATE_GENERATED < TRUNC(SYSDATE, 'IW'); 

DATE_GENERATED 
-------------- 
2016-02-07  
2016-02-06  
2016-02-05  
2016-02-04  
2016-02-03  
2016-02-02  
2016-02-01  

Или увидеть изменения года, позволяет вернуться дальше, опять же, как демо:

with lastweek(date_generated) as (
    select sysdate - level from dual connect by level <= 50 
) 
SELECT LASTWEEK.DATE_GENERATED 
FROM LASTWEEK 
WHERE LASTWEEK.DATE_GENERATED >= TRUNC(SYSDATE - 42, 'IW') 
AND LASTWEEK.DATE_GENERATED < TRUNC(SYSDATE - 35, 'IW'); 

DATE_GENERATED 
-------------- 
2016-01-03  
2016-01-02  
2016-01-01  
2015-12-31  
2015-12-30  
2015-12-29  
2015-12-28  
6

Я бы не стал использовать TO_CHAR в этом случае в целом ... оставаться в формате DATE ... безопаснее, особенно при прохождении лет ..

where trunc(LASTWEEK.DATE_GENERATED,'IW') = trunc(sysdate-7,'IW') 

Это единственное условие должно дать его вам :)

Вы можете увидеть, что он делает здесь:

1 with w_data as (select sysdate-level d from dual connect by level <= 20) 
    2 select d, trunc(d, 'IW') w 
    3* from w_data 
    SQL>/

    D     W 
    -------------------- -------------------- 
    09-feb-2016 13:20:41 08-feb-2016 00:00:00 
    08-feb-2016 13:20:41 08-feb-2016 00:00:00 
    07-feb-2016 13:20:41 01-feb-2016 00:00:00 
    06-feb-2016 13:20:41 01-feb-2016 00:00:00 
    05-feb-2016 13:20:41 01-feb-2016 00:00:00 
    04-feb-2016 13:20:41 01-feb-2016 00:00:00 
    03-feb-2016 13:20:41 01-feb-2016 00:00:00 
    02-feb-2016 13:20:41 01-feb-2016 00:00:00 
    01-feb-2016 13:20:41 01-feb-2016 00:00:00 
    31-jan-2016 13:20:41 25-jan-2016 00:00:00 
    30-jan-2016 13:20:41 25-jan-2016 00:00:00 
    29-jan-2016 13:20:41 25-jan-2016 00:00:00 
    28-jan-2016 13:20:41 25-jan-2016 00:00:00 
    27-jan-2016 13:20:41 25-jan-2016 00:00:00 
    26-jan-2016 13:20:41 25-jan-2016 00:00:00 
    25-jan-2016 13:20:41 25-jan-2016 00:00:00 
    24-jan-2016 13:20:41 18-jan-2016 00:00:00 
    23-jan-2016 13:20:41 18-jan-2016 00:00:00 
    22-jan-2016 13:20:41 18-jan-2016 00:00:00 
    21-jan-2016 13:20:41 18-jan-2016 00:00:00 

    20 rows selected. 
1

запрос от Дитто будет работать, но он не будет использовать индексы «LASTWEEK ,DATE_GENERATED»столбец, из прикладной функции (Trunc), поэтому я хотел бы пойти на следующее:

select 
    next_day(to_date('2016-01-10','yyyy-mm-dd')-14, 'MONDAY'), 
    next_day(to_date('2016-01-10','yyyy-mm-dd')-14, 'SUNDAY') 
from dual; 

Выход:

12/28/2015  01/03/2016 

Таким образом, ваш запрос будет:

WHERE LASTWEEK.DATE_GENERATED 
between next_day(to_date('2016-01-10','yyyy-mm-dd')-14, 'MONDAY') 
and next_day(to_date('2016-01-10','yyyy-mm-dd')-14, 'SUNDAY') 
+1

Хороший вопрос об индексах, но имейте в виду, что имена дней должны быть в NLS_DATE_LANGUAGE текущей сессии, что может сделать его более хрупким, чем кажется. Также использование между будет только безопасно, если 'date_generated' всегда имеет время, установленное на полночь, иначе записи после полуночи в воскресенье будут пропущены. –

Смежные вопросы