добавление рабочих дней в oracle sql - PullRequest
0 голосов
/ 15 октября 2018

У меня есть два поля даты: DATE_FIELD_ONE = 30/30/2018 и DATE_FIELD_TWO = DATE_FIELD_ONE + 20. Мне нужно выяснить, каким должно быть DATE_FIELD_TWO, если я добавляю только 20 рабочих дней.Как бы я это сделал?Я подумал, может быть, пытаясь «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

Ответы [ 3 ]

0 голосов
/ 15 октября 2018

вы можете определить рабочие дни так, как вам нравится, если вы используете функцию 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;
/
0 голосов
/ 17 октября 2018

Я понимаю, что у вас уже есть ответ, но за то, что оно того стоит, с этим мы постоянно сталкиваемся и имеем то, что оказалось очень хорошим решением.

По сути, мы поддерживаемотдельная таблица, называемая «рабочими днями», в которой есть все мыслимые даты, которые мы когда-либо сравнивали (и это определение, конечно, будет варьироваться от приложения к приложению - но в любом случае оно никогда не будет «огромным» по стандартам RDBMS).Существует логический флаг, который указывает, является ли дата рабочим днем ​​или выходным / праздничным днем, но, что более важно, существует значение индекса, которое увеличивается только в рабочие дни.Таблица выглядит следующим образом:

enter image description here

Преимуществом этого является прозрачность и масштабируемость.Если вы хотите, чтобы разница между двумя датами в рабочих днях:

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).Например, если вам нужно что-то в субботу, а суббота не является рабочим днем, это означает, что вам нужно в пятницу.И наоборот, если что-то должно быть доставлено в субботу, а суббота не в рабочий день, то это означает, что это будет доступно в понедельник.Контекст работы с нерабочими днями отличается, и этот метод позволяет вам выбрать правильный.

В качестве конечной точки продажи этот параметр позволяет также определять выходные как нерабочие дни... и вы можете сделать это или не делать это;тебе решать.Решение разрешает любой вариант.Теоретически можно добавить еще два столбца только для выходных с индексом рабочего дня, которые предоставят вам оба варианта.

0 голосов
/ 15 октября 2018

Вы можете попробовать это:

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.

PS Игнорируется случай государственных праздников, которые отличаются от одной культуры к другой, в зависимости от вопросабыть связанным только с выходными.

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

, который повторяется на следующий день, как в этом случае, если этот праздник не совпадает с выходным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...