Oracle Where (OR) 中的 IF/CASE 语句
IF / CASE statement in Where in Oracle (OR)
我想搜索两个日期之间的行。在每一行中都有一个带有日期的列。我想将此日期减 1,并始终显示该列减 1 天的结果。
例如 - 我正在 2021-07-08 00:00:00 和 2021-07-08 23:59:59[ 之间搜索=155=] 所以我想搜索日期为 2021-07-09 的列,但将它们显示为 2021-07-08.
问题是我想从搜索中排除节假日和周末。因此,例如,如果我将在 2021-07-09 00:00:00 和 2021-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:00 和 2021-07-07 23:59:59[= 之间搜索12=]
结果:
id
姓名
截止日期
1
电费
2021-07-07
在 2021-07-08 00:00:00 和 2021-07-08 23:59:59[= 之间搜索12=]
结果:
id
姓名
截止日期
1
水费单
2021-07-08
在 2021-07-09 00:00:00 和 2021-07-09 23:59:59[= 之间搜索12=]
结果:
id
姓名
截止日期
1
租金单
2021-07-09
在 2021-07-07 00:00:00 和 2021-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
我想搜索两个日期之间的行。在每一行中都有一个带有日期的列。我想将此日期减 1,并始终显示该列减 1 天的结果。
例如 - 我正在 2021-07-08 00:00:00 和 2021-07-08 23:59:59[ 之间搜索=155=] 所以我想搜索日期为 2021-07-09 的列,但将它们显示为 2021-07-08.
问题是我想从搜索中排除节假日和周末。因此,例如,如果我将在 2021-07-09 00:00:00 和 2021-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:00 和 2021-07-07 23:59:59[= 之间搜索12=]
结果:
id | 姓名 | 截止日期 |
---|---|---|
1 | 电费 | 2021-07-07 |
在 2021-07-08 00:00:00 和 2021-07-08 23:59:59[= 之间搜索12=]
结果:
id | 姓名 | 截止日期 |
---|---|---|
1 | 水费单 | 2021-07-08 |
在 2021-07-09 00:00:00 和 2021-07-09 23:59:59[= 之间搜索12=]
结果:
id | 姓名 | 截止日期 |
---|---|---|
1 | 租金单 | 2021-07-09 |
在 2021-07-07 00:00:00 和 2021-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