Как создать статистическую функцию пользователя в SQL, которая возвращает дату после добавления сочетания рабочих и календарных дней? - PullRequest
0 голосов
/ 19 апреля 2019

Я работаю над проектом, который намеревается измерить сроки выполнения определенных событий с фактическими датами событий.Мне нужно рассчитать сроки выполнения в SQL на 3 уровнях.3-й уровень содержит все этапы, необходимые для всего процесса, и у меня есть файл основных данных, содержащий количество дней, которое должно занять событие, которое должно быть выполнено.

На уровне 2 мне нужно использовать основные данные с уровня3 и суммируйте их, чтобы иметь представление высокого уровня.Таким образом, если время выполнения заказа AB составляет 3 дня, а BC - 5 дней, AC - 8 дней (3 + 5).

Проблема заключается в том, что некоторые этапы измеряются в рабочих днях, а некоторые - в календарных днях.Я написал функцию add_working_days () в SQL на уровне строк (уровень 3) и могу использовать SUM (время выполнения) OVER (PARTITION BY "Leve 2 View"), чтобы получить общее количество рабочих дней или календарных дней (если все вехи измеряются одинаково), а затем рассчитать срок выполнения в зависимости от того, какой мне нужно.Но когда мне нужно добавить количество рабочих и календарных дней, я застреваю.

+--------------+-----------------+------------------+----------------+---------------------+-----------------+--------------------+------------------+
| Order Number | L3 Trigger Flag | L3 Trigger Value | L3 Target Flag | L3 Agreed Lead Time | L3 Type of Days | L3 Target Due Date | L3 Calendar Days |
+--------------+-----------------+------------------+----------------+---------------------+-----------------+--------------------+------------------+
| ABC          | TEN             | 23/07/2018 00:00 | PK             |                   5 | Working Day(s)  | 30/07/2018 00:00   |                7 |
| ABC          | PK              | 27/07/2018 09:48 | AD             |                   6 | Calendar Day(s) | 02/08/2018 00:00   |                6 |
| ABC          | AD              | 04/08/2018 12:00 | AR             |                  26 | Calendar Day(s) | 30/08/2018 00:00   |               26 |
| ABC          | AR              | 28/08/2018 11:59 | DEL            |                   2 | Working Day(s)  | 30/08/2018 00:00   |                2 |
+--------------+-----------------+------------------+----------------+---------------------+-----------------+--------------------+------------------+

Я пытался преобразовать все вехи, измеренные в рабочих днях, в календарные дни (например, поле "L3 Calendar Days"), но это будет из-за триггерных дат на уровне 3, которые не обязательно должны совпадать с теми же днями недели при расчете на уровне 2. Таким образом, сумма для ABC заказа L3 календарных дней будет составлять 41 день, исходя из того, как яв данный момент рассчитываю.На уровне 2 мне нужно будет найти Целевую дату исполнения от TEN до DEL в этом примере, поэтому применение 41 календарного дня к 23/07/2018 даст мне дату 02/09/2018.

+--------------+-----------------+------------------+----------------+---------------------+-----------------+--------------------+------------------+-----------------+------------------+----------------+---------------------+-----------------+--------------------+
| Order Number | L3 Trigger Flag | L3 Trigger Value | L3 Target Flag | L3 Agreed Lead Time | L3 Type of Days | L3 Target Due Date | L3 Calendar Days | L2 Trigger Flag | L2 Trigger Value | L2 Target Flag | L2 Agreed Lead Time | L2 Type of Days | L2 Target Due Date |
+--------------+-----------------+------------------+----------------+---------------------+-----------------+--------------------+------------------+-----------------+------------------+----------------+---------------------+-----------------+--------------------+
| ABC          | TEN             | 23/07/2018 00:00 | PK             |                   5 | Working Day(s)  | 30/07/2018 00:00   |                7 | TEN             | 23/07/2018 00:00 | DEL            |                  41 | Calendar Day(s) | 02/09/2018 00:00   |
| ABC          | PK              | 27/07/2018 09:48 | AD             |                   6 | Calendar Day(s) | 02/08/2018 00:00   |                6 | TEN             | 23/07/2018 00:00 | DEL            |                  41 | Calendar Day(s) | 02/09/2018 00:00   |
| ABC          | AD              | 04/08/2018 12:00 | AR             |                  26 | Calendar Day(s) | 30/08/2018 00:00   |               26 | TEN             | 23/07/2018 00:00 | DEL            |                  41 | Calendar Day(s) | 02/09/2018 00:00   |
| ABC          | AR              | 28/08/2018 11:59 | DEL            |                   2 | Working Day(s)  | 30/08/2018 00:00   |                2 | TEN             | 23/07/2018 00:00 | DEL            |                  41 | Calendar Day(s) | 02/09/2018 00:00   |
+--------------+-----------------+------------------+----------------+---------------------+-----------------+--------------------+------------------+-----------------+------------------+----------------+---------------------+-----------------+--------------------+

Если бы мне пришлось разбить этот пример вручную, я должен был бы подать заявку с 23/07/2018, 5 рабочих дней (7 календарных дней, поэтому моя новая дата - 30/07/2018), а затем 6 календарных дней (поэтому моя новая дата будет 05/08/2018), затем 26 календарных дней (таким образом, моя новая дата будет 31/08/2018) и, наконец, 2 рабочих дня (4 календарных дня, поэтому моя новая дата будет 04/09/2018)

Моим ожидаемым результатом будет таблица, в которой согласованное время выполнения L2 показывает 43 календарных дня, а срок выполнения задания L2 показывает 04/09/2018

+--------------+-----------------+------------------+----------------+---------------------+-----------------+--------------------+------------------+-----------------+------------------+----------------+---------------------+-----------------+--------------------+
| Order Number | L3 Trigger Flag | L3 Trigger Value | L3 Target Flag | L3 Agreed Lead Time | L3 Type of Days | L3 Target Due Date | L3 Calendar Days | L2 Trigger Flag | L2 Trigger Value | L2 Target Flag | L2 Agreed Lead Time | L2 Type of Days | L2 Target Due Date |
+--------------+-----------------+------------------+----------------+---------------------+-----------------+--------------------+------------------+-----------------+------------------+----------------+---------------------+-----------------+--------------------+
| ABC          | TEN             | 23/07/2018 00:00 | PK             |                   5 | Working Day(s)  | 30/07/2018 00:00   |                7 | TEN             | 23/07/2018 00:00 | DEL            |                  43 | Calendar Day(s) | 04/09/2018 00:00   |
| ABC          | PK              | 27/07/2018 09:48 | AD             |                   6 | Calendar Day(s) | 02/08/2018 00:00   |                6 | TEN             | 23/07/2018 00:00 | DEL            |                  43 | Calendar Day(s) | 04/09/2018 00:00   |
| ABC          | AD              | 04/08/2018 12:00 | AR             |                  26 | Calendar Day(s) | 30/08/2018 00:00   |               26 | TEN             | 23/07/2018 00:00 | DEL            |                  43 | Calendar Day(s) | 04/09/2018 00:00   |
| ABC          | AR              | 28/08/2018 11:59 | DEL            |                   2 | Working Day(s)  | 30/08/2018 00:00   |                2 | TEN             | 23/07/2018 00:00 | DEL            |                  43 | Calendar Day(s) | 04/09/2018 00:00   |
+--------------+-----------------+------------------+----------------+---------------------+-----------------+--------------------+------------------+-----------------+------------------+----------------+---------------------+-----------------+--------------------+

Я думаю, мне нужно будетсоздать функцию, которая работает как

due_dt("L2 Trigger Value","L3 Agreed Lead Time", "L3 Type of Days") OVER (PARTITION BY "Order Number")

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

Редактировать: мне удалось создать функцию, которая принимаетдата, строка в виде списка дней, разделенных '|'и тип дней, разделенных '|'в соответствии с приведенным ниже описанием и циклически перебирает строку, чтобы добавить дату

create or replace Function add_group_days(Start_Date Date, nrDays Varchar2, dayType Varchar2) Return Date As
--Returns a date as a result of adding multiple numbers of working and calendar days. Syntax to be used: ADD_GROUP_DAYS(DATE,'NR|NR...','WD or CD|WD or CD')
--Example syntax: ADD_GROUP_DAYS(SYSDATE,'1|2|2|3','WD|CD|CD|WD')
--If number of arguments for the nrDays and dayType (number of values between '|') are not the same then it will return null
--Nested function: ADD_WORKING_DAYS()
    End_Date Date;
Begin
    If Start_Date is null or nrDays is null or dayType is null Then
        Return null;
    Elsif regexp_count(nrDays,'[^|]+')<>regexp_count(dayType,'[^|]+') Then
        Return null;    
    Else
    End_Date := Trunc(Start_Date);
        For i in 1..regexp_count(nrDays,'[^|]+') Loop
            If regexp_substr(dayType,'[^|]+',1,i) not in ('WD','CD') Then
                Return null;
            Elsif regexp_substr(dayType,'[^|]+',1,i) in ('CD') Then
                End_Date := End_Date + To_Number(regexp_substr(nrDays,'[^|]+',1,i));
            Elsif regexp_substr(dayType,'[^|]+',1,i) in ('WD') Then
                End_Date := add_working_days(End_Date,To_Number(regexp_substr(nrDays,'[^|]+',1,i)));
            End If;
        End Loop;
    End If;
    Return End_Date;
End add_group_days;

Не уверен, насколько эффективен этот метод, хотя для его использования сначала нужно объединить количество дней в группе и типдней в одной группе.

...