Oracle Where (OR) 中的 IF/CASE 语句

IF / CASE statement in Where in Oracle (OR)

我想搜索两个日期之间的行。在每一行中都有一个带有日期的列。我想将此日期减 1,并始终显示该列减 1 天的结果。

例如 - 我正在 2021-07-08 00:00:002021-07-08 23:59:59[ 之间搜索=155=] 所以我想搜索日期为 2021-07-09 的列,但将它们显示为 2021-07-08.

问题是我想从搜索中排除节假日和周末。因此,例如,如果我将在 2021-07-09 00:00:002021-07-09 23:59:59 之间进行搜索,那么我想搜索日期为 2021-07-12 的列,并将它们显示为 2021-07-09.

假期我有一个清单:

    with BANKHOLIDAYSUK as(
select COLUMN_VALUE as HOLIDAYDATE
from table(sys.odcivarchar2list  (
TO_DATE('30/08/2021', 'DD/MM/YYYY')
,TO_DATE('27/12/2021', 'DD/MM/YYYY')
,TO_DATE('28/12/2021', 'DD/MM/YYYY')
,TO_DATE('01/01/2022', 'DD/MM/YYYY')
,TO_DATE('03/01/2022', 'DD/MM/YYYY')
,TO_DATE('15/04/2022', 'DD/MM/YYYY')
,TO_DATE('18/04/2022', 'DD/MM/YYYY')
,TO_DATE('02/05/2022', 'DD/MM/YYYY')
,TO_DATE('02/06/2022', 'DD/MM/YYYY')
,TO_DATE('03/06/2022', 'DD/MM/YYYY')
,TO_DATE('29/08/2022', 'DD/MM/YYYY')
,TO_DATE('26/12/2022', 'DD/MM/YYYY')
,TO_DATE('27/12/2022', 'DD/MM/YYYY')
,TO_DATE('01/01/2023', 'DD/MM/YYYY')
,TO_DATE('02/01/2023', 'DD/MM/YYYY')
,TO_DATE('07/04/2023', 'DD/MM/YYYY')
,TO_DATE('10/04/2023', 'DD/MM/YYYY')
,TO_DATE('01/05/2023', 'DD/MM/YYYY')
,TO_DATE('29/05/2023', 'DD/MM/YYYY')
,TO_DATE('28/08/2023', 'DD/MM/YYYY')
,TO_DATE('25/12/2023', 'DD/MM/YYYY')
,TO_DATE('26/12/2023', 'DD/MM/YYYY')
,TO_DATE('09/07/2021', 'DD/MM/YYYY')))
)

如何将我们有 :start:end 日期的 where 子句签入该列表或周末。

我试过:

where 
to_date(to_char(from_tz( cast( (o.DUEDATEUTC - 1)  as timestamp ), 'UTC' ) at time zone to_char(l.oracletimezone  ), 'YYYY-MM-DD HH24:MI:SS'), 'YYYY-MM-DD HH24:MI:SS') between :startDate and :endDate
OR (
(SELECT * FROM BANKHOLIDAYSUK WHERE HOLIDAYDATE = TO_DATE(:startdate, 'DD/MM/YYYY')) is not null 
and to_date(to_char(from_tz( cast( (o.DUEDATEUTC - 1)  as timestamp ), 'UTC' ) at time zone to_char(l.oracletimezone  ), 'YYYY-MM-DD HH24:MI:SS'), 'YYYY-MM-DD HH24:MI:SS') between :startDate and :endDate
)
  OR

(
((SELECT to_char(:startDate, 'd') FROM DUAL) = 5)
and to_date(to_char(from_tz( cast( (o.DUEDATEUTC - 3)  as timestamp ), 'UTC' ) at time zone to_char(l.oracletimezone  ), 'YYYY-MM-DD HH24:MI:SS'), 'YYYY-MM-DD HH24:MI:SS') between :startDate and :endDate
)

但查询的执行似乎一直在进行...

l.oracletimezone 是一个包含不同位置时区的列。

当然我也在select中使用递减。

没有 OR 语句它可以工作,但正如我所说,仅在星期一和星期四之间。如果我们在星期五日期之间 select 那么我们将一无所获,因为在周末之前没有 'DUEDATE'。

我的逻辑错了吗?

示例:

id 姓名 截止日期
1 电费 2021-07-08
2 水费单 2021-07-09
3 租金单 2021-07-12

2021-07-07 00:00:002021-07-07 23:59:59[= 之间搜索12=]

结果:

id 姓名 截止日期
1 电费 2021-07-07

2021-07-08 00:00:002021-07-08 23:59:59[= 之间搜索12=]

结果:

id 姓名 截止日期
1 水费单 2021-07-08

2021-07-09 00:00:002021-07-09 23:59:59[= 之间搜索12=]

结果:

id 姓名 截止日期
1 租金单 2021-07-09

2021-07-07 00:00:002021-07-09 23:59:59[= 之间搜索12=]

结果:

id 姓名 截止日期
1 电费 2021-07-07
2 水费单 2021-07-08
3 租金单 2021-07-09

您可以创建函数:

CREATE FUNCTION next_working_day(
  day IN DATE
) RETURN DATE
IS
  working_day DATE;
BEGIN
  working_day := day + CASE TRUNC(day) - TRUNC(day, 'IW')
                       WHEN 5 THEN 2 -- Saturday
                       WHEN 6 THEN 1 -- Sunday
                       ELSE 0        -- Weekday
                       END;
  
  WITH non_holiday_date ( day, skip ) AS (
    SELECT working_day,
           NVL2(
             b.holidaydate,
             CASE TRUNC(working_day) - TRUNC(working_day, 'IW')
             WHEN 4 THEN 3 -- Friday
             ELSE 1        -- Any other weekday
             END,
             0
           )
    FROM   DUAL d
           LEFT OUTER JOIN bankholidaysuk b
           ON (TRUNC(working_day) = b.holidaydate)
  UNION ALL
    SELECT day + skip,
           NVL2(
             b.holidaydate,
             CASE TRUNC(day) - TRUNC(day, 'IW')
             WHEN 4 THEN 3 -- Friday
             ELSE 1        -- Any other weekday
             END,
             0
           )
    FROM   non_holiday_date n
           LEFT OUTER JOIN bankholidaysuk b
           ON (TRUNC(day) + skip = b.holidaydate)
    WHERE  n.skip > 0
  )
  SELECT day
  INTO   working_day
  FROM   non_holiday_date
  WHERE  skip = 0;
  
  RETURN working_day;
END;
/

那么,如果你有样本数据:

CREATE TABLE your_table (id, name, duedateutc) AS
SELECT 1, 'Electricity bill', DATE '2021-08-20' FROM DUAL UNION ALL
SELECT 2, 'Water bill',       DATE '2021-08-23' FROM DUAL UNION ALL
SELECT 3, 'Rent bill',        DATE '2021-08-31' FROM DUAL UNION ALL
SELECT 4, 'XYZ bill',         DATE '2021-12-29' FROM DUAL;

CREATE TABLE BANKHOLIDAYSUK ( holidaydate ) as
SELECT DATE '2021-08-30' FROM DUAL UNION ALL
SELECT DATE '2021-12-27' FROM DUAL UNION ALL
SELECT DATE '2021-12-28' FROM DUAL;

然后:

SELECT *
FROM   your_table o
WHERE  o.duedateutc BETWEEN next_working_day( DATE '2021-08-19' + 1 )
                    AND     next_working_day( DATE '2021-08-19' + INTERVAL '23:59:59' HOUR TO SECOND + 1 )

获取第二天到期的账单并输出:

ID NAME DUEDATEUTC
1 Electricity bill 2021-08-20 00:00:00

和:

SELECT *
FROM   your_table o
WHERE  o.duedateutc BETWEEN next_working_day( DATE '2021-08-20' + 1 )
                    AND     next_working_day( DATE '2021-08-20' + INTERVAL '23:59:59' HOUR TO SECOND + 1 )

跳过周末并在下周一获取账单并输出:

ID NAME DUEDATEUTC
2 Water bill 2021-08-23 00:00:00

和:

SELECT *
FROM   your_table o
WHERE  o.duedateutc BETWEEN next_working_day( DATE '2021-08-27' + 1 )
                    AND     next_working_day( DATE '2021-08-27' + INTERVAL '23:59:59' HOUR TO SECOND + 1 )

跳过周末和周一节假日,下周二取单,输出:

ID NAME DUEDATEUTC
3 Rent bill 2021-08-31 00:00:00

和:

SELECT *
FROM   your_table o
WHERE  o.duedateutc BETWEEN next_working_day( DATE '2021-08-19' + 1 )
                    AND     next_working_day( DATE '2021-08-27' + INTERVAL '23:59:59' HOUR TO SECOND + 1 )

获取之前的所有账单,输出:

ID NAME DUEDATEUTC
1 Electricity bill 2021-08-20 00:00:00
2 Water bill 2021-08-23 00:00:00
3 Rent bill 2021-08-31 00:00:00

和:

SELECT *
FROM   your_table o
WHERE  o.duedateutc BETWEEN next_working_day( DATE '2021-12-24' + 1 )
                    AND     next_working_day( DATE '2021-12-24' + INTERVAL '23:59:59' HOUR TO SECOND + 1 )

跳过周末和2天圣诞假期,下周三收到账单,输出:

ID NAME DUEDATEUTC
4 XYZ bill 2021-12-29 00:00:00

db<>fiddle here