2013-10-02 2 views
0

Необходимо создать список календарей до «11-30-2014» в одном запросе. Но не все дни, только рабочие дни (с понедельника по пятницу) и за исключением праздников. Праздничные дни хранятся в таблице holidays. Специальная таблица dual в oracle DB используется для генерации.Сгенерировать календарь до специальной даты одним запросом

SELECT to_date(current_date + level-1,'MM-DD-YY') as Calendar 
FROM dual, holidays 
WHERE to_date(current_date,'MM-DD-YY')+level-1 <= to_date('11-30-14','MM-DD-YY') 
AND to_char(to_date(current_date,'MM-DD-YY')+level-1,'D') NOT IN (6,7) 
CONNECT BY level <= 365 
MINUS 
SELECT to_date(data,'MM-DD-YY') 
FROM holidays; 

Я сделал это, но я сердцем этот случай можно сделать с 4 строками. Более простой. Если кто-то знает, как сделать это проще, тогда спасибо!

+0

Почему вы ограничены до 365 дней, если хотите сгенерировать до 2014-30-11 годов, что более чем за год? Почему вы вызываете 'to_date()' для вещей, которые уже являются датами, - вы вводите зависимость от 'NLS_DATE_FORMAT', а также неэффективны? –

ответ

3

У вас есть бессмысленное крестовое соединение к таблице holidays в вашем первом from; вы можете перенести свое первое состояние where на connect by - предположительно без ограничения на 365 дней, что, по-видимому, не соответствует вашему заявленному требованию; Вы используете явные to_date() и неявные to_char() преобразования для удаления времени элемента current_date который вводит NLS_DATE_FORMAT зависимости и будут лучше trunc() все равно:

SELECT TRUNC(current_date) + level - 1 as Calendar 
FROM dual 
WHERE TO_CHAR(TRUNC(current_date) + level - 1, 'DY', 'NLS_DATE_LANGUAGE=ENGLISH') 
    NOT IN ('SAT', 'SUN') 
CONNECT BY TRUNC(current_date) + level - 1 <= date '2014-11-30' 
MINUS SELECT data FROM holidays 

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

Вы также могли бы сделать это вместо того, чтобы, используя not exists вместо minus:

SELECT * 
FROM (
    SELECT TRUNC(current_date) + level - 1 as Calendar 
    FROM dual 
    CONNECT BY TRUNC(current_date) + level - 1 <= date '2014-11-30' 
) t 
WHERE TO_CHAR(t.calendar, 'DY', 'NLS_DATE_LANGUAGE=ENGLISH') NOT IN ('SAT', 'SUN') 
AND NOT EXISTS (SELECT 1 FROM holidays h WHERE h.data = t.calendar) 

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

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