【问题标题】:count Sunday in plsql between two dates :date1 and :date2在两个日期之间计算 plsql 中的星期日:date1 和:date2
【发布时间】:2021-02-26 10:31:16
【问题描述】:

我知道在论坛上有很多工作要做,但是我尝试了很多东西,但出现错误,请在 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;

【问题讨论】:

    标签: oracle plsql oracle-sqldeveloper plsqldeveloper oraclereports


    【解决方案1】:

    你可以像下面这样重写你的函数。在 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 ), 'fmday', '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;
    /
    

    【讨论】:

      【解决方案2】:

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

      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 ), 'fmday', '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;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-03-30
        • 2019-09-06
        • 1970-01-01
        • 1970-01-01
        • 2015-10-13
        • 2021-08-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多