DB2 Sql, как использовать оператор case?

Я пытаюсь извлечь все даты окончания событий для событий, срок действия которых истекает через 2 рабочих дня. Итак, для пятницы и четверга мне нужны даты, которые заканчиваются через 4 дня или меньше, для дат субботы, которые заканчиваются через 3 дня, для дат воскресенья-среды, которые заканчиваются в течение 2 дней, и +3 для всех государственных праздников, которые перечислены в столбце dateval в tempdate .

Приведенный ниже скрипт не работает, он содержит только даты +2 дня. Я понимаю, что мне нужно использовать оператор case, но я действительно не понимаю, как это реализовать. У кого-нибудь есть идеи?

select event_end_date
from mdmins.table

/*separating by date to find expiring dates*/ 
where  (  (dayofweek(c.event_end_date) in (5,6) /*Friday & Thursday*/ 
and    date(c.event_end_date) < current_date + 4 days 
and    date(c.event_end_date) >= current_date) 
or     (dayofweek(c.event_end_date) in (1,2,3,4) /*All other days of week*/ 
and    date(c.event_end_date) < current_date + 2 days 
and    date(c.event_end_date) >= current_date) 
or     (dayofweek(c.event_end_date) = 7 /*Saturday - not that this should be needed, but just in case*/ 
and    date(c.event_end_date) < current_date + 3 days 
and    date(c.event_end_date) >= current_date) 
or     (date(c.event_end_date) < (select dateval from mdmins.tempdate where dateval = (current date + 3 days)) /*a holiday is on in 3 days, so 2 working days before*/ 
and    date(c.event_end_date) >= current_date) ) 

person user2590369    schedule 18.09.2014    source источник
comment
Я хотел бы использовать его следующим образом: где (дата (event_end_date) между (случай, когда dayofweek (current_date) в (5,6), затем (current_date + 4 days), иначе конец null) и (случай, когда dayofweek (current_date) в ( 5,6) затем current_date еще null end)) но пока не работает:/   -  person user2590369    schedule 18.09.2014
comment
Это не оператор CASE (что является реальной вещью), и он вам не нужен. У вас есть обычный файл календаря с workingDay логическим столбцом? Это значительно облегчило бы написание. Файлы календаря, без сомнения, являются одной из самых полезных аналитических таблиц. За исключением этого, создание временной/виртуальной таблицы с помощью CTE и VALUES(...) значительно упростило бы это.   -  person Clockwork-Muse    schedule 18.09.2014


Ответы (2)


Логически единственное, что различается между данными за неделю, — это то, насколько далеко вы смотрите вперед, поэтому ограничьте логику использованием случая:

...
where date(c.event_end_date) between current_date and current_date +
  case
    when dayofweek(c.event_end_date) in (5, 6) then 4
    when dayofweek(c.event_end_date) in (1, 2, 3, 4) then 2
    else 3
  end days
or (date(c.event_end_date) < (select dateval
  from mdmins.tempdate
  where dateval = (current date + 3 days)) 
  and date(c.event_end_date) >= current_date)
person Bohemian♦    schedule 18.09.2014
comment
Это действительно хороший момент. Мне нравится, как вы это устроили! К сожалению, я получаю ту же проблему, что и с моим исходным sql, он вытягивает только дни +2, хотя мы, скажем, 5 ... поэтому я получаю только вещи, срок действия которых истекает 19 и 20 числа: / - person user2590369; 18.09.2014
comment
Понятно!! это будет работать со сценарием ниже. Очевидно, нужно будет подождать до завтра, чтобы увидеть, работает ли он как надо, но пока он выглядит хорошо! где ((дата (c.event_end_date) между current_date и current_date + случай, когда день недели (текущая дата) в (5,6), затем 4, когда день недели (текущая дата) в (1, 2, 3, 4), затем 2, иначе 3 конец days) или date(c.event_end_date) ‹ (выберите dateval из mdmins.tempdate, где dateval = (текущая дата + 3 дня)) и date(c.event_end_date) ›= current_date ) - person user2590369; 18.09.2014
comment
Как насчет праздников? Если вам нужно принять это во внимание, то файл календаря, который упоминает @Clockwork-Muse, — это то, что вам нужно. - person Charles; 18.09.2014
comment
Да, у нас есть даты всех европейских государственных праздников в этом столбце dateval, поэтому здесь мы также устанавливаем буфер для них. Я уверен, что есть лучший способ сделать это, но наша система немного грязная :) - person user2590369; 18.09.2014

Это классический пример того, почему вам нужен календарь, включающий все даты и кучу дополнительной информации. Вы сможете сделать что-то похожее на это:

WITH Desired_Dates AS (SELECT MIN(calendarDate) AS startRange,
                              MAX(calendarDate) + 1 DAY AS endRange
                       FROM(SELECT calendarDate
                            FROM Calendar
                            WHERE calendarDate >= CURRENT_DATE
                                  AND dayOfWeekISO IN (1, 2, 3, 4, 5)
                                  AND isHolday = '0'
                            ORDER BY calendarDate
                            FETCH FIRST 3 ROWS ONLY) D)
SELECT C.<column_list
FROM <Your_Table> C
JOIN Desired_Dates D
  ON C.event_end_date >= D.startRange
     AND C.event_end_Date < D.endRange

(Обратите внимание, что я специально использую день недели по стандарту ISO, где понедельник равен 1. Воскресенье, поскольку 1 — это американское значение, и функции для получения дня недели из заданной даты: в зависимости от прихотей текущих настроек культуры. Кроме того, в случае, если event_end_date является чем-то вроде временной метки, вы хотите использовать эксклюзивный конечный диапазон
На самом деле это дает хорошие шансы использовать информацию только об индексе для получения желаемого даты (при условии соответствующего индекса) и в любом случае будет получать данные в CTE только один раз.

Если у вас нет таблицы календаря, вы можете сделать ее:

WITH Working_Dates AS (SELECT CURRENT_DATE - 1 DAY AS calendarDate, 
                              0 AS workingDayNum, '0' AS isWorkingDay
                       FROM SYSIBM/SYSDUMMY1
                       UNION ALL 
                       SELECT calendarDate, 
                              workingDayNum + CASE WHEN isWorkingDay = 1
                                                   THEN 1
                                                   ELSE 0 END AS workingDayNum,
                              isWorkingDay
                       FROM (SELECT calendarDate, workingDayNum,
                                    CASE WHEN DAYOFWEEK_ISO(WD.calendarDate) IN (6, 7)
                                              OR Holiday.dateval IS NOT NULL 
                                         THEN '0'
                                         ELSE '1' END AS isWorkingDay
                             FROM (SELECT calendarDate + 1 DAY, workingDayNum
                                   FROM Working_Dates
                                   WHERE workingDayNum < 2) WD
                             LEFT JOIN mdmins.tempdate Holiday
                                    ON Holiday.dateval = WD.calendarDate) WD),

     Desired_Dates AS (SELECT MIN(calendarDate) AS startRange,
                              MAX(calendarDate) + 1 DAY AS endRange
                       FROM Working_Date
                       WHERE isWorkingDay = '1')

SELECT C.<column_list
FROM <Your_Table> C
JOIN Desired_Dates D
  ON C.event_end_date >= D.startRange
     AND C.event_end_Date < D.endRange

Это использует рекурсивный CTE для циклического перебора дней от (на один до) текущей даты до тех пор, пока не пройдут три рабочих дня. (Мне пришлось начать на день раньше, поэтому мне пришлось написать логику «это рабочий день» только один раз, поэтому и все вложения).

Обратите внимание, что ни ваши первоначальные попытки, ни какие-либо из существующих ответов не учитывают их:

  1. Что произойдет, если в пятницу или понедельник будет выходной (пропустить 5 дней, а не 4)?
  2. Что произойдет, если будет несколько выходных дней подряд (неизвестное количество дней, которые нужно пропустить)?

Составляя список фактических рабочих дней, мы можем оградить себя от проблемы.

person Clockwork-Muse    schedule 20.09.2014