需要在一个查询中生成日历列表,直到“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 :(得分: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)
...它还将内部选择块中的日期生成分开,并将过滤器保持在一起,我认为这样更易于理解和维护。