在 plsql 中计算两个日期之间的星期日:date1 和:date2

问题描述

我知道论坛上有很多工作要做,但我尝试了很多东西,但得到错误,请我在oracle报告中有两个参数:date1和:date2我想检查星期日,然后返回给我这些星期日有多少个两个日期

function SUNDAY_CFormula return NUMBER is
start_date DATE := :DATE1;
end_date DATE := :DATE2;
A NUMBER;
begin
SELECT Count(*) 
FROM   (SELECT To_char(start_date + ( LEVEL - 1 ),'fmday')INTO A 
        FROM DUAL;   
        CONNECT BY LEVEL <= end_date - start_date + 1) 
WHERE  A IN ( 'sunday' );
RETURN A;
end;

解决方法

你可以像下面这样重写你的函数。在您的 to_char 函数中添加 'nls_date_language = english' 子句更安全,以使您的函数独立于您的默认环境设置。

create or replace 
function SUNDAY_CFormula (DATE1 date,DATE2 date) return NUMBER is
start_date DATE := DATE1;
end_date DATE := DATE2;
A NUMBER;
begin
SELECT Count(*) INTO A
FROM   (
       SELECT To_char(start_date + ( LEVEL - 1 ),'fmday','nls_date_language = english') A
        FROM DUAL 
        CONNECT BY LEVEL <= end_date - start_date + 1
        ) t
WHERE  t.A IN ( 'sunday' );
RETURN A;
end;
/

你甚至可以使用下面的版本来让你的函数更灵活地处理它作为参数的两个日期,无论 date1 是大于还是小于 date2。

create or replace 
function SUNDAY_CFormula (DATE1 date,DATE2 date) return NUMBER is
start_date DATE := DATE1;
end_date DATE := DATE2;
A NUMBER;
begin
SELECT Count(*) INTO A
FROM   (SELECT To_char(start_date + ( LEVEL - 1 ),'nls_date_language = english') A
        FROM DUAL 
        CONNECT BY LEVEL <= greatest(end_date,start_date) - least(end_date,start_date) + 1
        ) t
WHERE  t.A IN ( 'sunday' );
RETURN A;
end;
/
,

作为替代。我总是尝试为日期范围过程创建公式而不是“迭代”,我只是不喜欢生成数据就扔掉它。是的,有时是必要的,但在这种情况下不是。以下将完成您想要的:

create or replace 
function sunday_calc ( date1_in  date,date2_in  date,sun_in    varchar2 default 'sun'
                     ) 
  return number 
is
    sun_count integer; 
begin
    with date_range( start_date,end_date) as
         ( select trunc(least(date1_in,date2_in)),trunc(greatest(date1_in,date2_in))
             from dual
         ) 
    select floor((trunc(end_date) - trunc(next_day(start_date-1,sun_in))/7)) + 1
      into sun_count 
      from date_range;
    return sun_count;
end sunday_calc;

注意:不幸的是 next_day 函数不接受 NLS_DATE_LANGUAGE 参数,所以我创建了一个替代。 sun_in 参数:包含英文日'Sunday'对应的目标语言名称


与@MDO 的函数相比,对此感到好奇,我对每个函数进行了一些测试。他们产生了相同的结果; 除了,在某些情况下,开始日期大于结束日期,差异为 1。与实际日历相比,公式是正确的 (see fiddle)。但为什么,MDO 的逻辑似乎完全正确。那时我只需要知道为什么。花了一段时间,但她/他的代码中有一个小错误。事实证明,当开始日期大于结束日期时,他们的例程实际上开始查看最大日期的日期并向前推进。因此,更改周期会查看该日期加上天数中的较大日期。通过将最少的函数应用于“Select to_char(start_date...”,结果为:

create or replace 
function sunday_cformula_r (date1 date,date2 date) return number is
start_date date := date1;
end_date date := date2;
a number;
begin
select count(*) into a
from   (select to_char(least(end_date,start_date) + ( level - 1 ),'nls_date_language = english') a
        from dual 
        connect by level <= greatest(end_date,start_date) + 1
 
        ) t
where  t.a in ( 'sunday' );
return a;
end;