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

4

1 回答 1

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)

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

于 2013-10-02T14:13:46.913 回答