使用一个查询生成日历直到特殊日期

时间:2013-10-02 13:34:47

标签: sql database oracle oracle-sqldeveloper

需要在一个查询中生成日历列表,直到“11-30-2014”。但不是所有日子,只有工作日(周一至周五)和节假日除外。假日日期存储在holidays表中。 oracle DB中的特殊表dual用于生成。

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行完成。更简单。如果有人知道如何让这更容易,那么谢谢!

1 个答案:

答案 0 :(得分:3)

您在第一个holidays子句中与from表进行了无意义的交叉连接;你可以将你的第一个where条件移到connect by - 大概没有365天限制,这似乎与你声明的要求不一致;您正在使用明确的to_date()和隐式to_char()次转化来移除引入current_date依赖关系的NLS_DATE_FORMAT的时间元素,并且无论如何都会更好地使用trunc():< / p>

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)

...它还将内部选择块中的日期生成分开,并将过滤器保持在一起,我认为这样更易于理解和维护。