【问题标题】:adding business days in oracle sql在 oracle sql 中添加工作日
【发布时间】:2019-03-20 03:17:55
【问题描述】:

我有两个日期字段,DATE_FIELD_ONE = 8/30/2018 和 DATE_FIELD_TWO = DATE_FIELD_ONE + 20。如果我只添加了 20 个工作日,我需要找到 DATE_FIELD_TWO 应该是什么。我将如何做到这一点?我想也许可以尝试“DY”,但不知道如何让它发挥作用。谢谢。

CASE WHEN TO_CHAR(TO_DATE(DATE_FIELD_ONE),'DY')='SAT' THEN 1 ELSE 0 END
CASE WHEN TO_CHAR(TO_DATE(DATE_FIELD_ONE),'DY')='SUN' THEN 1 ELSE 0 END

【问题讨论】:

标签: sql oracle


【解决方案1】:

你可以试试这个:

select max(date_field_two) as date_field_two
  from
 (
 select date'2018-08-30'+  
    cast(case when to_char(date'2018-08-30'+level,'D','NLS_DATE_LANGUAGE=ENGLISH') 
                                              in ('6','7') then 
            0
          else
            level
          end as int) as date_field_two, 
 sum(cast(case when to_char(date'2018-08-30'+level,'D','NLS_DATE_LANGUAGE=ENGLISH')  
                                               in ('6','7') then 
            0
          else
            1
          end as int)) over (order by level) as next_day
      from dual
    connect by level <= 20*1.5 
-- 20 is the day to be added, every time 5(#of business days)*1.5 > 7(#of week days)
-- 7=5+2<5+(5/2)=5*(1+1/2)=5*1.5 [where 1.5 is just a coefficient might be replaced a greater one like 2]
-- so 4*5*1.5=20*1.5 > 4*7 
  )    
 where next_day = 20;

 DATE_FIELD_TWO
-----------------
   27.09.2018

通过使用connect by dual 子句。

附:忽略了公共假期的情况,这取决于一种文化与另一种文化的不同,这取决于仅与周末相关的问题。

Rextester Demo

编辑:假设您在 '2018-09-25' 和 '2018-09-26' (在这组日子里)有国定假日,那么考虑以下几点:

select max(date_field_two) as date_field_two
  from
 (
 select date'2018-08-30'+  
        (case when to_char(date'2018-08-30'+level,'D','NLS_DATE_LANGUAGE=ENGLISH') 
                                              in ('6','7') then 
               0
              when date'2018-08-30'+level in (date'2018-09-25',date'2018-09-26') then
               0
              else
               level
              end) as date_field_two, 
 sum(cast(case when to_char(date'2018-08-30'+level,'D','NLS_DATE_LANGUAGE=ENGLISH')  
                                               in ('6','7') then 
                0
               when date'2018-08-30'+level in (date'2018-09-25',date'2018-09-26') then
                0 
               else
                1
               end as int)) over (order by level) as next_day
      from dual
    connect by level <= 20*2 
  )    
 where next_day = 20;

 DATE_FIELD_TWO
-----------------
   01.10.2018

下一天迭代,就像本例一样,除非这个假期与周末重合。

【讨论】:

  • 你是怎么想出 1.5 的?
  • @smattiko84 7=5+2&lt;5+(5/2)=5*(1+1/2)=5*1.5,这是一周之内,您可以扩展为任何其他值。其实这个值并不重要,你也可以选择2作为系数来满足条件。
  • 如果我确实想添加几个美国假期,我将如何修改?
【解决方案2】:

如果您使用 PL/SQL 函数,您可以任意定义工作日

这里有一个简单的原型 - 没有任何假期 - 但可以使用相同的逻辑对其进行调整。

create or replace function add_business_days (from_date IN date, bd IN integer) return date as 
  fd date := trunc(from_date,'iw'); 
  cnt int := (from_date-fd)+bd-1; 
  ww int := ceil(cnt/5); 
  wd int := mod(cnt,5); 
begin
  return from_date + (ww*7)+wd; 
end;
/

【讨论】:

    【解决方案3】:

    我知道您已经有了答案,但值得一提的是,这是我们一直在处理的问题,并且已经证明是一个非常好的解决方案。

    实际上,我们维护了一个名为“工作日”的单独表格,其中包含我们可以比较的每个可能的日期(当然,该定义会因应用程序而异 - 但无论如何它永远不会是“巨大的” 按 RDBMS 标准)。有一个布尔标志指示日期是工作日还是周末/节假日,但更重要的是,有一个仅在工作日递增的索引值。该表如下所示:

    这样做的好处是透明度和可扩展性。如果您想要工作日中两个日期之间的差异:

    select
      h.entry_date, h.invoice_date, wd2.workday_index - wd1.workday_index as delta
    from
      sales_order_data h
      join util.work_days wd1 on h.sales_order_entry_dte = wd1.cal_date
      join util.work_days wd2 on h.invoice_dte = wd2.cal_date
    

    如果您需要在表格中取一个日期并加上 20 天(如您原来的问题陈述):

    select
      h.date_field_1, wd2.cal_date as date_field_1_plus_20
    from
      my_table h
      join util.work_days wd1 on h.date_field_1 = wd1.cal_date
      join util.work_days wd2 on
        wd1.workday_index + 20 = wd2.workday_index and
        wd2.is_workday
    

    (免责声明,这是在 PostgreSQL 中,这就是我使用布尔值的原因。在 Oracle 中,我猜您需要将其更改为整数并说 =1

    此外,对于附加问题,这还提供了两种不同的选项来定义“工作日”,一个向前滚动,另一个向后滚动(因此有 workday_index 和 workday_index_back)。例如,如果您在星期六需要某些东西,而星期六不是工作日,这意味着您在星期五需要它。相反,如果某件东西要在星期六交付,而星期六不是工作日,那么这意味着它将在星期一可用。如何处理非工作日的情况不同,这种方法让您可以选择合适的。

    作为最终卖点,此选项允许您也将假期定义为非工作日......您可以这样做或不这样做;由你决定。该解决方案允许任一种选择。理论上,您可以为工作日索引周末再添加两列,这样您就有两种选择。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-05-09
      • 1970-01-01
      • 1970-01-01
      • 2021-11-01
      • 1970-01-01
      • 2013-05-04
      • 1970-01-01
      相关资源
      最近更新 更多