2013-10-02 41 views
0

需要在一个查询中生成日历列表直到“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线来完成。更简单。如果有人有任何想法如何使这更容易,那么谢谢!

+0

如果您想要生成2014年至11月11日,这是一年多的时间,为什么限制为365天?你为什么要调用'to_date()'来处理已经是日期的事情 - 你引入了对'NLS_DATE_FORMAT'的依赖,以及效率低下? –

回答

3

您在第一条from子句中与表holidays有无意义的交叉连接;您可以将您的第一个where条件转换为connect by - 大概没有365天限制,这似乎与您声明的要求不符;您正在使用显式to_date()和隐式转换to_char()删除其引入了NLS_DATE_FORMAT依赖current_date时间元素,并会与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) 

...这也分开在内部选择块的日期生成和过滤器保持在一起,我认为这是一个有点更容易理解和维护。