查询:使用is_working_day标签获取一天中的上一个工作日

时间:2019-10-17 07:32:33

标签: sql oracle

从2010年1月1日至2030年12月31日全天,我们使用实例化视图。 有一个与标记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

基本上,我使用Oracle的LAG()函数仅获取一个工作日的前一个工作日,但是必须使用LEAD()函数获取一个封闭日的最后一个工作日。如果有连续的休息日,则必须使用与连续的休息日一样多的LEAD()函数。

我认为有一种更好的方法来获取所有连续关闭日的前一个工作日。

1 个答案:

答案 0 :(得分:2)

您可以将LAGIGNORE 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 | null             | Friday              |              0
02-JAN-10 | null             | Saturday            |              0
03-JAN-10 | null             | Sunday              |              0
04-JAN-10 | null             | 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 <>提琴here

查询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

db <>提琴here