【问题标题】:Oracle query to get the number of business days between 2 datesOracle查询以获取2个日期之间的工作日数
【发布时间】:2019-06-19 13:47:10
【问题描述】:

我们正在使用 Oracle 11。

在我们的 CASE WHEN 语句中,我需要检查两个日期之间的天数是否大于 3 个工作日(因此不包括周末和节假日)。

那么,如果

日期 1 = 2019 年 1 月 21 日(星期一)

日期 2 = 2019 年 1 月 18 日(星期五)

Date1 和 Date2 之间的工作日数是 1 天,而不是 3 天。

CASE WHEN TO_DATE(SETTLEMENT_DATE, 'YYYY-MM-DD') - TO_DATE(TRADE_DATE, 
'YYYY-MM-DD')  > 3  THEN 0  --> this includes weekend and holidays
WHEN CODE = 1 THEN 1
WHEN CODE =2 THEN 2
ELSE 3
END AS MyColumn

谢谢。

【问题讨论】:

    标签: sql oracle date oracle11g


    【解决方案1】:

    你可以创建一个使用conditional aggregation作为的函数

    SQL> alter session set NLS_TERRITORY="AMERICA"
    SQL> create or replace function get_working_days( 
                                                 i_settlement_date tab.settlement_date%type, 
                                                 i_trade_date      tab.trade_date%type
                                               ) return pls_integer is
      o_working_days  pls_integer;                                         
    begin
      select nvl(sum(case when
                  to_char(trade_date + level,'Dy') in ('Sat','Sun') 
                 then 0
                 else 1
                 end ),0)
      into o_working_days
      from tab
     where settlement_date >= trade_date
     connect by level <= i_settlement_date - i_trade_date + 1;
    
     return o_working_days;
    end; 
    

    获取两个日期之间的工作日,包括两个边界日期。

    即它为您的案例返回2,包括mondayfriday

    编辑:如果您不想创建函数,请将以下查询与替换变量 &amp;i_settlement_date&amp;i_trade_date 一起使用:

      select nvl(sum(case when
                  to_char(trade_date + level,'Dy') in ('Sat','Sun') 
                 then 0
                 else 1
                 end ),0) as working_days
      from tab
     where settlement_date >= trade_date
     connect by level <= &i_settlement_date - &i_trade_date + 1;
    

    并在出现提示时分别输入示例值date'2019-01-21'date'2019-01-18'

    【讨论】:

    • to_char(trade_date + level,'D','NLS_DATE_LANGUAGE=AMERICAN') 的结果取决于当前用户会话NLS_TERRITORY'NLS_DATE_LANGUAGE=AMERICAN' 对此无效。使用to_char(trade_date + level,'Dy','NLS_DATE_LANGUAGE=AMERICAN') in ('Sat','Sun')
    • @WernfriedDomscheit 好的,从之前的讨论中回忆起您对 territory 的看法是正确的,谢谢。
    • 谢谢。这个声明会改变每个人的 NLS_TERRITORY,还是只改变我的会话?由于我无权在 Oracle 上创建函数,有没有办法在没有函数的情况下创建函数?
    • @faujong 不客气。它只影响您的会话,对于所有受影响的数据库,使用alter system 并且大部分需要重新启动。我正在编辑答案,以便您执行没有功能的查询。
    【解决方案2】:

    您不需要使用分层查询,并且可以独立于 NLS 设置使用 TRUNC( date_value, 'IW' ) 来查找 ISO 周的开始,这始终是星期一。

    ( TRUNC( end_date, 'IW' ) - TRUNC( start_date, 'IW' ) ) * 5 / 7
    

    将查找包含开始日期的 ISO 周的开始与包含结束日期的 ISO 周的开始之间的工作日数。

    然后只需添加最后一周的工作日:

    + LEAST( TRUNC( end_date   ) - TRUNC( end_date,   'IW' ) + 1, 5 )
    

    并减去开始日期前第一个 ISO 周的天数:

    - LEAST( TRUNC( start_date ) - TRUNC( start_date, 'IW' ), 5 )
    

    放在一起给出:

    Oracle 设置

    CREATE TABLE table_name ( start_date, end_date ) AS
    SELECT DATE '2018-12-30' + LEVEL, DATE '2019-01-10' 
    FROM DUAL
    CONNECT BY LEVEL <= 11
    

    查询

    SELECT TO_CHAR( start_date, 'YYYY-MM-DD "("DY")"') AS start_date,
    
           ( TRUNC( end_date, 'IW' ) - TRUNC( start_date, 'IW' ) ) * 5 / 7
           + LEAST( TRUNC( end_date   ) - TRUNC( end_date,   'IW' ) + 1, 5 )
           - LEAST( TRUNC( start_date ) - TRUNC( start_date, 'IW' ), 5 )
             AS Num_Week_Days
    FROM   table_name;
    

    输出

    START_DATE | NUM_WEEK_DAYS :--------------- | ------------: 2018-12-31 (周一) | 9 2019-01-01 (周二) | 8 2019-01-02 (周三) | 7 2019-01-03 (星期四) | 6 2019-01-04 (周五) | 5 2019-01-05 (周六) | 4 2019-01-06 (太阳) | 4 2019-01-07 (周一) | 4 2019-01-08 (周二) | 3 2019-01-09 (周三) | 2 2019-01-10 (周四) | 1

    db小提琴here

    【讨论】:

    • 感谢大家的帮助。我最终使用了 MT0 的解决方案。但是,如何在此查询中排除假期?假设我有一个假期日历表,其中包含所有假期的列 HolidayDates,例如:2018 年 12 月 25 日、2018 年 12 月 31 日等。
    • @faujong stackoverflow.com/questions/43632677/… 如果这不能回答您的问题,那么您应该提出一个新问题,因为它超出了此问题的范围。
    猜你喜欢
    • 2019-06-23
    • 2019-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多