Запрос: Получить предыдущий рабочий день дня с тегом is_working_day - PullRequest
0 голосов
/ 17 октября 2019

Мы используем материализованное представление со всеми днями с 01.01.2010 по 31.12.2030. Есть поле даты, связанное с флагом is_working_day 0 / 1.

Мне нужно получить предыдущий рабочий день дня.

Пример: мы 01/01 / n, предыдущийрабочий день 31/12 / n-1. Мы 02/01 / n, предыдущий рабочий день также 31/12 / n-1.

У меня есть тестовый код здесь: https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=215d5e6aa6673f2273f3766f58093bc6

образец таблицы:

DATE_D  DAY_OF_WEEK_DESC_EN     IS_WORKING_DAY
01-JAN-10   Friday      0
02-JAN-10   Saturday    0
03-JAN-10   Sunday      0
04-JAN-10   Monday      1
05-JAN-10   Tuesday     1
06-JAN-10   Wednesday   1
07-JAN-10   Thursday    1
08-JAN-10   Friday      1
09-JAN-10   Saturday    0
10-JAN-10   Sunday      0
select 
date_d, 
lag(date_d) over (order by date_d) as last_working_day, 
day_of_week_desc_en
from oracle_calendar
where is_working_day = 1

Ожидаемый:

DATE_D  LAST_WORKING_DAY    DAY_OF_WEEK_DESC_EN     IS_WORKING_DAY
01-JAN-10               Friday      0
02-JAN-10               Saturday    0
03-JAN-10   04-JAN-10   Sunday      0
04-JAN-10   04-JAN-10   Monday      1
05-JAN-10   04-JAN-10   Tuesday     1
06-JAN-10   05-JAN-10   Wednesday   1
07-JAN-10   06-JAN-10   Thursday    1
08-JAN-10   07-JAN-10   Friday      1
09-JAN-10   08-JAN-10   Saturday    0
10-JAN-10   08-JAN-10   Sunday      0

В основном я использую функцию LAG () Oracle, чтобы получить только предыдущий рабочий день рабочего дня, но я должен использовать LEAD ()функция, чтобы получить последний рабочий день закрытого дня. Если есть последовательные закрытые дни, я должен использовать эту функцию LEAD () столько, сколько существует последовательных закрытых дней.

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

1 Ответ

2 голосов
/ 17 октября 2019

Вы можете использовать LAG с предложением IGNORE NULLS и оператором CASE:

Тестовые данные :

CREATE TABLE oracle_calendar (
  DATE_D              DATE,
  DAY_OF_WEEK_DESC_EN VARCHAR2(9) GENERATED ALWAYS AS ( CAST( RTRIM( TO_CHAR( DATE_D, 'Day' ) ) AS VARCHAR2(9) ) ),
  IS_WORKING_DAY      NUMBER(1,0)
);

INSERT INTO oracle_calendar( date_d, is_working_day )
SELECT DATE '2010-01-01', 0 FROM DUAL UNION ALL
SELECT DATE '2010-01-02', 0 FROM DUAL UNION ALL
SELECT DATE '2010-01-03', 0 FROM DUAL UNION ALL
SELECT DATE '2010-01-04', 1 FROM DUAL UNION ALL
SELECT DATE '2010-01-05', 1 FROM DUAL UNION ALL
SELECT DATE '2010-01-06', 1 FROM DUAL UNION ALL
SELECT DATE '2010-01-07', 1 FROM DUAL UNION ALL
SELECT DATE '2010-01-08', 1 FROM DUAL UNION ALL
SELECT DATE '2010-01-09', 0 FROM DUAL UNION ALL
SELECT DATE '2010-01-10', 0 FROM DUAL;

Запрос:

SELECT date_d, 
       LAG( CASE is_working_day WHEN 1 THEN date_d END, 1, NULL )
         IGNORE NULLS OVER ( ORDER BY date_d) AS last_working_day, 
       day_of_week_desc_en,
       is_working_day
FROM   oracle_calendar

Выход :

DATE_D    | LAST_WORKING_DAY | DAY_OF_WEEK_DESC_EN | IS_WORKING_DAY
:-------- | :--------------- | :------------------ | -------------:
01-JAN-10 | <em>null</em>             | Friday              |              0
02-JAN-10 | <em>null</em>             | Saturday            |              0
03-JAN-10 | <em>null</em>             | Sunday              |              0
04-JAN-10 | <em>null</em>             | Monday              |              1
05-JAN-10 | 04-JAN-10        | Tuesday             |              1
06-JAN-10 | 05-JAN-10        | Wednesday           |              1
07-JAN-10 | 06-JAN-10        | Thursday            |              1
08-JAN-10 | 07-JAN-10        | Friday              |              1
09-JAN-10 | 08-JAN-10        | Saturday            |              0
10-JAN-10 | 08-JAN-10        | Sunday              |              0

db <> скрипка здесь

Запрос 2 :

Чтобы избавиться от всех значений NULL при запуске и использовать первый рабочий день:

SELECT date_d, 
       COALESCE(
         LAG( CASE is_working_day WHEN 1 THEN date_d END, 1, NULL )
           IGNORE NULLS OVER ( ORDER BY date_d),
         CASE is_working_day
         WHEN 1
         THEN date_d
         ELSE LEAD( CASE is_working_day WHEN 1 THEN date_d END, 1, NULL )
           IGNORE NULLS OVER ( ORDER BY date_d)
         END
       ) AS last_working_day,
       day_of_week_desc_en,
       is_working_day
FROM   oracle_calendar
DATE_D    | LAST_WORKING_DAY | DAY_OF_WEEK_DESC_EN | IS_WORKING_DAY
:-------- | :--------------- | :------------------ | -------------:
01-JAN-10 | 04-JAN-10        | Friday              |              0
02-JAN-10 | 04-JAN-10        | Saturday            |              0
03-JAN-10 | 04-JAN-10        | Sunday              |              0
04-JAN-10 | 04-JAN-10        | Monday              |              1
05-JAN-10 | 04-JAN-10        | Tuesday             |              1
06-JAN-10 | 05-JAN-10        | Wednesday           |              1
07-JAN-10 | 06-JAN-10        | Thursday            |              1
08-JAN-10 | 07-JAN-10        | Friday              |              1
09-JAN-10 | 08-JAN-10        | Saturday            |              0
10-JAN-10 | 08-JAN-10        | Sunday              |              0

дБ <> скрипка здесь

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