在今天的两个时间之间生成时隙
Generating Time slots between two time for today
我正在稍微编辑我的问题
我有Office Timing Table如下。
TIME_FROM TIME_TO TIME_FROM1 TIME_TO1 TIME_FROM2 TIME_TO2
07:00 AM 14:00 PM 700 1400 06/08/2020 07:00:00 AM 06/08/2020 02:00:00 PM
16:00 PM 18:00 PM 1600 1800 06/08/2020 04:00:00 PM 06/08/2020 06:00:00 PM
办公室开始时间为早上 7 点,结束时间为下午 6 点,休息时间在 between.This 时间可能因所选办公室而异。
输入参数为
1.Travel 到达办公室的时间(以分钟为单位)
2.Time 时段持续时间(分钟)
考虑到以分钟为单位的旅行时间后,我想在这些时间范围之间生成 15 分钟(可变)间隔的时隙,例如
上午 7 点
上午 7 点 15 分
上午 7 点 30 分
早上 7 点 45 分
上午 8 点
.
.
.
.
下午 1.30
下午 1.45
下午 2 点
二班从这里开始
下午 4 点
下午 4 点 15 分
下午 4.30
.
.
.
.
.
下午 5 点 30 分
下午 5 点 45 分
场景一:
所需行程时间:31 分钟
预订尝试时间 6.15 AM
办公时间早上 7 点
要求的结果
7.00
7.15
.
。
1.45 PM(不包括班次结束时间 2.00PM)
下午 4 点
下午 4 点 15 分
.
。
下午 5 点 45 分
场景二:
所需行程时间:31 分钟
预订尝试时间 6.45 AM
办公时间早上 7 点
要求的结果
7.16
7.31
.
。
1.46 PM(不包括班次结束时间 2.00PM)
下午 4 点
下午 4 点 15 分
.
。
下午 5 点 45 分
场景三:
所需行程时间:31 分钟
预订尝试时间上午 9 点 45 分
办公时间早上 7 点
要求的结果
10.16
10.31
.
。
1.46 PM(不包括班次结束时间 2.00PM)
下午 4 点
下午 4 点 15 分
.
。
下午 5 点 45 分
场景 4:
所需行程时间:31 分钟
预订尝试时间下午 3 点
办公室二班上班时间下午 4.00
要求的结果
下午 4 点
04.15 下午
.
。
5.45 PM(不包括班次结束时间 18.00PM)
场景 5:
所需行程时间:31 分钟
预订尝试时间下午 3.45
办公室二班上班时间下午 4.00
要求的结果
04.16 下午
04.31 下午
.
。
5.46 PM(不包括班次结束时间 18.00PM)
WITH
--cte to determine office hours, this is probably a table irl
office_timing (id, time_from2, time_to2) AS
(
SELECT 1, TO_DATE('09/08/2020 07:00:00 AM','DD/MM/YYYY HH:MI:SS AM'), TO_DATE('09/08/2020 02:00:00 PM','DD/MM/YYYY HH:MI:SS AM') FROM dual UNION ALL
SELECT 2, TO_DATE('09/08/2020 04:00:00 PM','DD/MM/YYYY HH:MI:SS AM'), TO_DATE('09/08/2020 06:00:00 PM','DD/MM/YYYY HH:MI:SS AM') FROM dual
)
--cte to determine when travel time to office, replace with other values to test. Make this a variable if it is an input parameter
,travel_time (travel_mins) AS
(
SELECT 31 FROM DUAL
)
--cte to determine slot length, replace with other values to test. Make this a variable if it is an input parameter
,
slot_minutes (mins) AS
(
SELECT 15 FROM DUAL
)
--cte to determine when query is run, replace with other values to test. Make this a variable if it is an input parameter
,run_date_tab (run_date) AS
(
SELECT
TO_DATE('09/08/2020 03:45:00 PM','DD/MM/YYYY HH:MI:SS AM') + travel_mins/1440
FROM travel_time
)
--cte to determine start time based on the query run date
-- if run date is in a time slot then take run date
-- if run date is outside time slot then take closest future start date
,
start_time_tab (qry_start_time) AS
(
SELECT MIN(CASE
WHEN t.time_from2 <= r.run_date AND t.time_to2 > r.run_date
THEN r.run_date
WHEN t.time_from2 > r.run_date
THEN t.time_from2
ELSE
NULL
END)
FROM run_date_tab r
CROSS JOIN office_timing t
)
,slots (slot_start_time) AS
(
SELECT
s.qry_start_time +(level - 1) / ((60/m.mins)*24)
FROM start_time_tab s CROSS JOIN slot_minutes m CONNECT BY
level < 100
)
SELECT TO_CHAR(s.slot_start_time,'DD/MM/YYYY HH:MI:SS AM')
FROM slots s
JOIN office_timing t ON t.time_from2 < s.slot_start_time AND t.time_to2 > s.slot_start_time;
Oracle提供了相当完善的日期(包括时间戳)处理函数。通常我遵循这样一个公理,即一旦列被转换为日期,唯一的原因就是转换为字符串以创建显示列。但是也有例外。其中之一是(经常)需要对日期进行切片、切块和重新组合。这就是根据您的 'match the minute run' 要求正确计算结束时间的情况。
您不会从 SQL 解决方案中获得换档换行符,至少我会这样做。您可以通过迭代结果来使用 PL/SQL。然而,这对于您的表示层来说是一项简单的任务。我在最终结果中添加了一列来指示转变。考虑到这一点:
with time_range (sts, ets) as
( select case when extract(hour from systimestamp) <= 07
then trunc(systimestamp) + interval '07:00' hour to minute
else trunc(systimestamp, 'mi')
end sot
, case when extract(hour from systimestamp) <= 07
then trunc(systimestamp) + interval '18:00' hour to minute
else to_timestamp(to_char(systimestamp,'yyyymmdd') || '18' || to_char(systimestamp,'mi'), 'yyyymmddhh24mi')
end eot
from dual
)
, office_hours (start_time, end_time) as
( select * from time_range
union all
select start_time+interval '15' minute, end_time
from office_hours
where start_time < end_time
)
select to_char(start_time, 'hh.mi am')
, case when 60 * extract(hour from cast( start_time as timestamp))
+ extract(minute from cast( start_time as timestamp)) <= 14*60
then 'first shift'
else 'second shift'
end shift
from office_hours;
它的作用:
查询的工作是在 2 个 CTE 和 select 中使用它们完成的:
- time_range:确定给定所需的开始和结束时间
当前时间(在服务器上)。
- office_hours:计算 15 分钟间隔的递归 CTE
开始到结束时间。
- 主要:Select 范围的开始并确定移位。
参见 fiddle example。注意:在当前形式下,查询将始终 return 至少 1 行。如果运行在结束时间之后,则return是该时间的一行指示。
还有 2 个稍微修改的附加查询允许实际指定 运行 时间而不是从系统中获取时间。对于这些,我将它们中的 运行time" 分别设置为 07:00 和 09:02。
我正在稍微编辑我的问题
我有Office Timing Table如下。
TIME_FROM TIME_TO TIME_FROM1 TIME_TO1 TIME_FROM2 TIME_TO2
07:00 AM 14:00 PM 700 1400 06/08/2020 07:00:00 AM 06/08/2020 02:00:00 PM
16:00 PM 18:00 PM 1600 1800 06/08/2020 04:00:00 PM 06/08/2020 06:00:00 PM
办公室开始时间为早上 7 点,结束时间为下午 6 点,休息时间在 between.This 时间可能因所选办公室而异。
输入参数为
1.Travel 到达办公室的时间(以分钟为单位)
2.Time 时段持续时间(分钟)
考虑到以分钟为单位的旅行时间后,我想在这些时间范围之间生成 15 分钟(可变)间隔的时隙,例如
上午 7 点
上午 7 点 15 分
上午 7 点 30 分
早上 7 点 45 分
上午 8 点 .
.
.
.
下午 1.30
下午 1.45
下午 2 点
二班从这里开始
下午 4 点
下午 4 点 15 分
下午 4.30
.
.
.
.
.
下午 5 点 30 分
下午 5 点 45 分
场景一:
所需行程时间:31 分钟
预订尝试时间 6.15 AM
办公时间早上 7 点
要求的结果
7.00
7.15
.
。 1.45 PM(不包括班次结束时间 2.00PM)
下午 4 点
下午 4 点 15 分
.
。 下午 5 点 45 分
场景二:
所需行程时间:31 分钟
预订尝试时间 6.45 AM
办公时间早上 7 点
要求的结果
7.16
7.31
.
。 1.46 PM(不包括班次结束时间 2.00PM)
下午 4 点
下午 4 点 15 分
.
。 下午 5 点 45 分
场景三:
所需行程时间:31 分钟
预订尝试时间上午 9 点 45 分
办公时间早上 7 点
要求的结果
10.16
10.31
.
。 1.46 PM(不包括班次结束时间 2.00PM)
下午 4 点
下午 4 点 15 分
.
。 下午 5 点 45 分
场景 4:
所需行程时间:31 分钟
预订尝试时间下午 3 点
办公室二班上班时间下午 4.00
要求的结果
下午 4 点
04.15 下午
.
。 5.45 PM(不包括班次结束时间 18.00PM)
场景 5:
所需行程时间:31 分钟
预订尝试时间下午 3.45
办公室二班上班时间下午 4.00
要求的结果
04.16 下午
04.31 下午
.
。 5.46 PM(不包括班次结束时间 18.00PM)
WITH
--cte to determine office hours, this is probably a table irl
office_timing (id, time_from2, time_to2) AS
(
SELECT 1, TO_DATE('09/08/2020 07:00:00 AM','DD/MM/YYYY HH:MI:SS AM'), TO_DATE('09/08/2020 02:00:00 PM','DD/MM/YYYY HH:MI:SS AM') FROM dual UNION ALL
SELECT 2, TO_DATE('09/08/2020 04:00:00 PM','DD/MM/YYYY HH:MI:SS AM'), TO_DATE('09/08/2020 06:00:00 PM','DD/MM/YYYY HH:MI:SS AM') FROM dual
)
--cte to determine when travel time to office, replace with other values to test. Make this a variable if it is an input parameter
,travel_time (travel_mins) AS
(
SELECT 31 FROM DUAL
)
--cte to determine slot length, replace with other values to test. Make this a variable if it is an input parameter
,
slot_minutes (mins) AS
(
SELECT 15 FROM DUAL
)
--cte to determine when query is run, replace with other values to test. Make this a variable if it is an input parameter
,run_date_tab (run_date) AS
(
SELECT
TO_DATE('09/08/2020 03:45:00 PM','DD/MM/YYYY HH:MI:SS AM') + travel_mins/1440
FROM travel_time
)
--cte to determine start time based on the query run date
-- if run date is in a time slot then take run date
-- if run date is outside time slot then take closest future start date
,
start_time_tab (qry_start_time) AS
(
SELECT MIN(CASE
WHEN t.time_from2 <= r.run_date AND t.time_to2 > r.run_date
THEN r.run_date
WHEN t.time_from2 > r.run_date
THEN t.time_from2
ELSE
NULL
END)
FROM run_date_tab r
CROSS JOIN office_timing t
)
,slots (slot_start_time) AS
(
SELECT
s.qry_start_time +(level - 1) / ((60/m.mins)*24)
FROM start_time_tab s CROSS JOIN slot_minutes m CONNECT BY
level < 100
)
SELECT TO_CHAR(s.slot_start_time,'DD/MM/YYYY HH:MI:SS AM')
FROM slots s
JOIN office_timing t ON t.time_from2 < s.slot_start_time AND t.time_to2 > s.slot_start_time;
Oracle提供了相当完善的日期(包括时间戳)处理函数。通常我遵循这样一个公理,即一旦列被转换为日期,唯一的原因就是转换为字符串以创建显示列。但是也有例外。其中之一是(经常)需要对日期进行切片、切块和重新组合。这就是根据您的 'match the minute run' 要求正确计算结束时间的情况。
您不会从 SQL 解决方案中获得换档换行符,至少我会这样做。您可以通过迭代结果来使用 PL/SQL。然而,这对于您的表示层来说是一项简单的任务。我在最终结果中添加了一列来指示转变。考虑到这一点:
with time_range (sts, ets) as
( select case when extract(hour from systimestamp) <= 07
then trunc(systimestamp) + interval '07:00' hour to minute
else trunc(systimestamp, 'mi')
end sot
, case when extract(hour from systimestamp) <= 07
then trunc(systimestamp) + interval '18:00' hour to minute
else to_timestamp(to_char(systimestamp,'yyyymmdd') || '18' || to_char(systimestamp,'mi'), 'yyyymmddhh24mi')
end eot
from dual
)
, office_hours (start_time, end_time) as
( select * from time_range
union all
select start_time+interval '15' minute, end_time
from office_hours
where start_time < end_time
)
select to_char(start_time, 'hh.mi am')
, case when 60 * extract(hour from cast( start_time as timestamp))
+ extract(minute from cast( start_time as timestamp)) <= 14*60
then 'first shift'
else 'second shift'
end shift
from office_hours;
它的作用:
查询的工作是在 2 个 CTE 和 select 中使用它们完成的:
- time_range:确定给定所需的开始和结束时间 当前时间(在服务器上)。
- office_hours:计算 15 分钟间隔的递归 CTE 开始到结束时间。
- 主要:Select 范围的开始并确定移位。
参见 fiddle example。注意:在当前形式下,查询将始终 return 至少 1 行。如果运行在结束时间之后,则return是该时间的一行指示。
还有 2 个稍微修改的附加查询允许实际指定 运行 时间而不是从系统中获取时间。对于这些,我将它们中的 运行time" 分别设置为 07:00 和 09:02。