在今天的两个时间之间生成时隙

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 中使用它们完成的:

  1. time_range:确定给定所需的开始和结束时间 当前时间(在服务器上)。
  2. office_hours:计算 15 分钟间隔的递归 CTE 开始到结束时间。
  3. 主要:Select 范围的开始并确定移位。

参见 fiddle example。注意:在当前形式下,查询将始终 return 至少 1 行。如果运行在结束时间之后,则return是该时间的一行指示。
还有 2 个稍微修改的附加查询允许实际指定 运行 时间而不是从系统中获取时间。对于这些,我将它们中的 运行time" 分别设置为 07:00 和 09:02。