Oracle 每月计算天数

Oracle count days per month

我写了这个SQL语句来计算每个月的天数

(select count(*) DAYs FROM
    (
     select trunc(ADD_MONTHS(sysdate,-1),'MM') +  level -1 Dates from dual connect by
      level <= ADD_MONTHS(trunc(sysdate,'MM'),1)-1 -  trunc(sysdate,'MM')+1
   ) Where To_char(dates,'DY') NOT IN ('SA','SO'))

目前此语句忽略星期六和星期日,它从 sysdate 之前的月份(6 月)开始计算天数。

6 月有 22 天没有周末,但遗憾的是我的声明说它有 23 天。我发现它包括 7 月 1 日,这是错误的。

你知道我怎么知道我的小声明它只计算我想要获得的月份的天数,不包括另一个月份的天数吗?

做这种事情总是看起来不好看...这里有一种方法,它在整个当年都这样做。您可以通过向 where 子句添加附加语句来限制为一个月:

 select to_char(trunc(sysdate, 'y') + level - 1, 'fmMON') as month, count(*)
   from dual
  where to_char(trunc(sysdate, 'y') + level - 1, 'fmDY', 'nls_date_language=english') not in ('SAT','SUN')
connect by level <= trunc(add_months(sysdate, 12), 'y') - trunc(sysdate, 'y')
  group by to_char(trunc(sysdate, 'y') + level - 1, 'fmMON')

正如我所说,不漂亮。

注意几件事:

  • 使用 fm format model modifier 删除前导空格
  • 明确使用 nls_date_language 以确保它在所有环境中都能正常工作
  • 为了简单起见,我在当前日期上增加了 12 个月,然后将其截断到 1 月 1 日以获得新年的第一天
  • 如果您想按月执行此操作,可能值得查看 LAST_DAY() 函数

上个月的相同语句(使用 LAST_DAY())将是:

 select count(*)
   from dual
  where to_char(trunc(sysdate, 'y') + level - 1, 'fmDY', 'nls_date_language=english') not in ('SAT','SUN')
connect by level <= last_day(add_months(trunc(sysdate, 'mm'), -1)) - add_months(trunc(sysdate, 'mm'), -1) + 1

首先,您的内部查询 (select trunc(ADD_MONTHS(sysdate,-1),'MM') + level -1 Dates from dual connect by level <= ADD_MONTHS(trunc(sysdate,'MM'),1)-1 - trunc(sysdate,'MM')+1) returns 这个月的天数加上下个月的额外一天。

其次,更简单的查询可以使用 LAST_DAY 函数来获取月份的最后一天。

最后,使用 'D' 日期格式获取星期几。

SELECT COUNT(*) FROM (
  SELECT TO_CHAR(TRUNC(SYSDATE,'MM') + ROWNUM - 1, 'D') d
  FROM dual CONNECT BY LEVEL <= TO_NUMBER(TO_CHAR(LAST_DAY(SYSDATE),'DD'))
) WHERE d BETWEEN 1 AND 5;

无需生成一个月中的所有日期然后计算它们:

SQL Fiddle

Oracle 11g R2 模式设置:

CREATE FUNCTION WORK_DAYS_IN_MONTH(
  dt DATE
) RETURN NUMBER DETERMINISTIC
AS
  first_day DATE   := TRUNC( dt, 'MM' );
  remainder NUMBER := LAST_DAY( dt ) - ( first_day + INTERVAL '27' DAY );
BEGIN
  RETURN 20 + CASE first_day - TRUNC( first_day, 'IW' )
                   WHEN 0 THEN remainder                  -- Monday
                   WHEN 1 THEN remainder                  -- Tuesday
                   WHEN 2 THEN remainder                  -- Wednesday
                   WHEN 3 THEN LEAST( remainder, 2 )      -- Thursday
                   WHEN 4 THEN LEAST( remainder, 1 )      -- Friday
                   WHEN 5 THEN GREATEST( remainder-2, 0 ) -- Saturday
                          ELSE GREATEST( remainder-1, 0 ) -- Sunday
                   END;
END;
//

查询 1:

SELECT ADD_MONTHS( DATE '2014-12-01', LEVEL ) AS "Month",
       WORK_DAYS_IN_MONTH( ADD_MONTHS( DATE '2014-12-01', LEVEL ) ) AS "# Work Days"
FROM   DUAL
CONNECT BY LEVEL <= 12

Results:

|                       Month | # Work Days |
|-----------------------------|-------------|
|   January, 01 2015 00:00:00 |          22 |
|  February, 01 2015 00:00:00 |          20 |
|     March, 01 2015 00:00:00 |          22 |
|     April, 01 2015 00:00:00 |          22 |
|       May, 01 2015 00:00:00 |          21 |
|      June, 01 2015 00:00:00 |          22 |
|      July, 01 2015 00:00:00 |          23 |
|    August, 01 2015 00:00:00 |          21 |
| September, 01 2015 00:00:00 |          22 |
|   October, 01 2015 00:00:00 |          22 |
|  November, 01 2015 00:00:00 |          21 |
|  December, 01 2015 00:00:00 |          23 |