我有两个日期字段,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
答案 0 :(得分: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
子句。
P.S。忽略公共假期的情况,公共假期因一种文化与另一种文化而异,具体取决于仅与周末有关的问题。
编辑: 假设您在“ 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 :(得分:0)
如果使用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;
/
答案 2 :(得分:0)
我知道您已经有了答案,但值得的是,我们一直在处理这件事,事实证明这是一个很好的解决方案。
实际上,我们维护着一个单独的表,称为“工作日”,该表具有我们可以比较的所有可能的日期(当然,每个应用程序的定义都会有所不同-但是在任何情况下,它都不会“很大(按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)。例如,如果您在星期六需要,而星期六不是工作日,则意味着您在星期五需要它。相反,如果要在周六交付某物,而周六不在工作日,则意味着它将在周一开放。处理非工作日的上下文各不相同,这种方法使您可以选择合适的工作日。
作为最终卖点,此选项使您也可以将假期定义为非工作日...,您可以执行此操作或不执行此操作;由你决定。该解决方案允许任何一种选择。从理论上讲,您只能在周末的工作日索引中再添加两列,这给了您两个选择。