Oracle SQL 获取最后一年的日期,不包括周末

问题描述

我希望这能够为我提供过去 12 个月(不包括周末)的日历日期列表;但它只是给了我完整的日期列表 - 我认为这很好 - 但想知道为什么下面不正确。

SELECT ADD_MONTHS(Trunc(SYSDATE,'MM'),-12) - 1 + rownum AS CalendarDate
FROM all_objects
WHERE ADD_MONTHS(Trunc(SYSDATE,-12) - 1 + rownum <= sysdate
AND to_char(sysdate,'DY') NOT IN ('SAT','SUN')

解决方法

您使用 to_char(sysdate,'DY') 检查今天是星期日还是星期一。您需要检查在您的窗口中不可用的 CalendarDate。您可以使用 cte 来计算日历,然后您可以按照以下条件删除周末。

with cte (CalendarDate) as
(
SELECT ADD_MONTHS(TRUNC(SYSDATE,'MM'),-12) - 1 + rownum AS CalendarDate
FROM all_objects
WHERE ADD_MONTHS(TRUNC(SYSDATE,-12) - 1 + rownum <= sysdate
)
select * from cte where 
 to_char(CalendarDate,'DY') not in ('SAT','SUN');
| CALENDARDATE |
| :----------- |
| 02-MAR-20    |
| 03-MAR-20    |
| 04-MAR-20    |
| 05-MAR-20    |
| 06-MAR-20    |
| 09-MAR-20    |
| 10-MAR-20    |
| 11-MAR-20    |
| 12-MAR-20    |
| 13-MAR-20    |
| 16-MAR-20    |
| 17-MAR-20    |
| 18-MAR-20    |
| 19-MAR-20    |
| 20-MAR-20    |
| 23-MAR-20    |
| 24-MAR-20    |
| 25-MAR-20    |
| 26-MAR-20    |
| 27-MAR-20    |
| 30-MAR-20    |
| 31-MAR-20    |
| 01-APR-20    |
| 02-APR-20    |
| 03-APR-20    |
| 06-APR-20    |
| 07-APR-20    |
| 08-APR-20    |
| 09-APR-20    |
| 10-APR-20    |
| 13-APR-20    |
| 14-APR-20    |
| 15-APR-20    |
| 16-APR-20    |
| 17-APR-20    |
| 20-APR-20    |
| 21-APR-20    |
| 22-APR-20    |
| 23-APR-20    |
| 24-APR-20    |
| 27-APR-20    |
| 28-APR-20    |
| 29-APR-20    |
| 30-APR-20    |
| 01-MAY-20    |
| 04-MAY-20    |
| 05-MAY-20    |
| 06-MAY-20    |
| 07-MAY-20    |
| 08-MAY-20    |
| 11-MAY-20    |
| 12-MAY-20    |
| 13-MAY-20    |
| 14-MAY-20    |
| 15-MAY-20    |
| 18-MAY-20    |
| 19-MAY-20    |
| 20-MAY-20    |
| 21-MAY-20    |
| 22-MAY-20    |
| 25-MAY-20    |
| 26-MAY-20    |
| 27-MAY-20    |
| 28-MAY-20    |
| 29-MAY-20    |
| 01-JUN-20    |
| 02-JUN-20    |
| 03-JUN-20    |
| 04-JUN-20    |
| 05-JUN-20    |
| 08-JUN-20    |
| 09-JUN-20    |
| 10-JUN-20    |
| 11-JUN-20    |
| 12-JUN-20    |
| 15-JUN-20    |
| 16-JUN-20    |
| 17-JUN-20    |
| 18-JUN-20    |
| 19-JUN-20    |
| 22-JUN-20    |
| 23-JUN-20    |
| 24-JUN-20    |
| 25-JUN-20    |
| 26-JUN-20    |
| 29-JUN-20    |
| 30-JUN-20    |
| 01-JUL-20    |
| 02-JUL-20    |
| 03-JUL-20    |
| 06-JUL-20    |
| 07-JUL-20    |
| 08-JUL-20    |
| 09-JUL-20    |
| 10-JUL-20    |
| 13-JUL-20    |
| 14-JUL-20    |
| 15-JUL-20    |
| 16-JUL-20    |
| 17-JUL-20    |
| 20-JUL-20    |
| 21-JUL-20    |
| 22-JUL-20    |
| 23-JUL-20    |
| 24-JUL-20    |
| 27-JUL-20    |
| 28-JUL-20    |
| 29-JUL-20    |
| 30-JUL-20    |
| 31-JUL-20    |
| 03-AUG-20    |
| 04-AUG-20    |
| 05-AUG-20    |
| 06-AUG-20    |
| 07-AUG-20    |
| 10-AUG-20    |
| 11-AUG-20    |
| 12-AUG-20    |
| 13-AUG-20    |
| 14-AUG-20    |
| 17-AUG-20    |
| 18-AUG-20    |
| 19-AUG-20    |
| 20-AUG-20    |
| 21-AUG-20    |
| 24-AUG-20    |
| 25-AUG-20    |
| 26-AUG-20    |
| 27-AUG-20    |
| 28-AUG-20    |
| 31-AUG-20    |
| 01-SEP-20    |
| 02-SEP-20    |
| 03-SEP-20    |
| 04-SEP-20    |
| 07-SEP-20    |
| 08-SEP-20    |
| 09-SEP-20    |
| 10-SEP-20    |
| 11-SEP-20    |
| 14-SEP-20    |
| 15-SEP-20    |
| 16-SEP-20    |
| 17-SEP-20    |
| 18-SEP-20    |
| 21-SEP-20    |
| 22-SEP-20    |
| 23-SEP-20    |
| 24-SEP-20    |
| 25-SEP-20    |
| 28-SEP-20    |
| 29-SEP-20    |
| 30-SEP-20    |
| 01-OCT-20    |
| 02-OCT-20    |
| 05-OCT-20    |
| 06-OCT-20    |
| 07-OCT-20    |
| 08-OCT-20    |
| 09-OCT-20    |
| 12-OCT-20    |
| 13-OCT-20    |
| 14-OCT-20    |
| 15-OCT-20    |
| 16-OCT-20    |
| 19-OCT-20    |
| 20-OCT-20    |
| 21-OCT-20    |
| 22-OCT-20    |
| 23-OCT-20    |
| 26-OCT-20    |
| 27-OCT-20    |
| 28-OCT-20    |
| 29-OCT-20    |
| 30-OCT-20    |
| 02-NOV-20    |
| 03-NOV-20    |
| 04-NOV-20    |
| 05-NOV-20    |
| 06-NOV-20    |
| 09-NOV-20    |
| 10-NOV-20    |
| 11-NOV-20    |
| 12-NOV-20    |
| 13-NOV-20    |
| 16-NOV-20    |
| 17-NOV-20    |
| 18-NOV-20    |
| 19-NOV-20    |
| 20-NOV-20    |
| 23-NOV-20    |
| 24-NOV-20    |
| 25-NOV-20    |
| 26-NOV-20    |
| 27-NOV-20    |
| 30-NOV-20    |
| 01-DEC-20    |
| 02-DEC-20    |
| 03-DEC-20    |
| 04-DEC-20    |
| 07-DEC-20    |
| 08-DEC-20    |
| 09-DEC-20    |
| 10-DEC-20    |
| 11-DEC-20    |
| 14-DEC-20    |
| 15-DEC-20    |
| 16-DEC-20    |
| 17-DEC-20    |
| 18-DEC-20    |
| 21-DEC-20    |
| 22-DEC-20    |
| 23-DEC-20    |
| 24-DEC-20    |
| 25-DEC-20    |
| 28-DEC-20    |
| 29-DEC-20    |
| 30-DEC-20    |
| 31-DEC-20    |
| 01-JAN-21    |
| 04-JAN-21    |
| 05-JAN-21    |
| 06-JAN-21    |
| 07-JAN-21    |
| 08-JAN-21    |
| 11-JAN-21    |
| 12-JAN-21    |
| 13-JAN-21    |
| 14-JAN-21    |
| 15-JAN-21    |
| 18-JAN-21    |
| 19-JAN-21    |
| 20-JAN-21    |
| 21-JAN-21    |
| 22-JAN-21    |
| 25-JAN-21    |
| 26-JAN-21    |
| 27-JAN-21    |
| 28-JAN-21    |
| 29-JAN-21    |
| 01-FEB-21    |
| 02-FEB-21    |
| 03-FEB-21    |
| 04-FEB-21    |
| 05-FEB-21    |
| 08-FEB-21    |
| 09-FEB-21    |
| 10-FEB-21    |
| 11-FEB-21    |
| 12-FEB-21    |
| 15-FEB-21    |
| 16-FEB-21    |
| 17-FEB-21    |
| 18-FEB-21    |
| 19-FEB-21    |
| 22-FEB-21    |
| 23-FEB-21    |
| 24-FEB-21    |
| 25-FEB-21    |
| 26-FEB-21    |
| 01-MAR-21    |
| 02-MAR-21    |
| 03-MAR-21    |
| 04-MAR-21    |
| 05-MAR-21    |
| 08-MAR-21    |
| 09-MAR-21    |

dbfiddle here

,

因为你这样做:

AND to_char(sysdate,'DY') NOT IN ('SAT','SUN')

而且今天不是周六或周日。您需要查看计算出的 CalendarDate 值;但是您不能在同一级别的子查询中执行此操作。您可以尝试重新计算它:

AND to_char(ADD_MONTHS(TRUNC(SYSDATE,-12) - 1 + rownum,'SUN')

但这不会返回任何行 - 至少在当前运行时。碰巧的是,2020 年 3 月 1 日是星期日,因此被排除在外;并且由于 rownum 生成的时间和方式,该结果被排除,下一个看到相同的值,该值被排除,依此类推。

您可以使用内联视图来避免这两个问题:

SELECT CalendarDate
FROM (
  SELECT ADD_MONTHS(TRUNC(SYSDATE,-12) - 1 + rownum AS CalendarDate
  FROM all_objects
  WHERE ADD_MONTHS(TRUNC(SYSDATE,-12) - 1 + rownum <= sysdate
)
WHERE to_char(CalendarDate,'DY','NLS_DATE_LANGUAGE=ENGLISH') NOT IN ('SAT','SUN')

CALENDARDATE
02-MAR-20
03-MAR-20
04-MAR-20
05-MAR-20
06-MAR-20
09-MAR-20
10-MAR-20
...

db<>fiddle

我添加了一个语言修饰符,以防止会话未设置为英语的用户出现不同的行为。

虽然查询 all_objects 并不理想,但最好使用分层查询:

SELECT *
FROM (
  SELECT ADD_MONTHS(TRUNC(SYSDATE,-12) - 1 + level AS CalendarDate
  FROM dual
  CONNECT BY level <= TRUNC(SYSDATE) - ADD_MONTHS(TRUNC(SYSDATE,-12) + 1
)
WHERE to_char(CalendarDate,'SUN')
ORDER BY CalendarDate

db<>fiddle

或递归 CTE,如果您是 11gR2+:

WITH rcte (CalendarDate) AS (
  SELECT ADD_MONTHS(TRUNC(SYSDATE,-12)
  FROM dual
  UNION ALL
  SELECT rcte.CalendarDate + interval '1' day
  FROM rcte
  WHERE rcte.CalendarDate < TRUNC(SYSDATE)
)
SELECT CalendarDate
FROM rcte
WHERE to_char(CalendarDate,'SUN')
ORDER BY CalendarDate

db<>fiddle(作为 18c,以避免其使用的 11g 版本中的补丁级别出现一些问题)。