Oracle SQL:两天之间的小时数,分钟数和秒数之间的时差,以及按日期划分/聚合的时间差

时间:2016-02-03 17:00:15

标签: oracle date aggregate break

这是一个表,其中包含一个任务的员工工作时间,该任务可能在两天(或更长时间)之间跨越,也可能不跨越。

需要帮助以按小时,分钟和秒的时间单独汇总每个员工和任务ID的日期。

表示例:

Emp_ID | Task_ID | Task_start_date_time   | Task_stop_date_time  
 A1    | 123     | 01/13/2016 11:30:30 PM |  01/14/2016 12:30:30 AM  
 B1    | 124     | 01/16/2016 10:30:35 PM |  01/18/2016  2:30:35 AM  
 C1    | 125     | 01/19/2016  9:30:20 AM |  01/19/2016  2:30:20 PM  
 D1    | 126     | 01/20/2016  3:15:25 AM |  01/21/2016  2:25:25 PM  

所需的SQL结果集:

A1 | 123 | 01/13/2016 | 00:29:30  
A1 | 123 | 01/14/2016 | 04:30:30  
B1 | 124 | 01/16/2016 | 01:29:25  
B1 | 124 | 01/17/2016 | 24:00:00  
B1 | 124 | 01/18/2016 | 02:30:35  
C1 | 125 | 01/19/2016 | 05:00:00  
D1 | 126 | 01/20/2016 | 20:44:35  
D1 | 126 | 01/20/2016 | 14:25:25  

提前致谢。

另外一个:eid和tid有多行?并且需要以相同的方式聚合。

表示例:

Emp_ID | Task_ID | Task_start_date_time   | Task_stop_date_time  
 A1    | 123     | 01/13/2016 11:30:30 PM |  01/14/2016 12:30:30 AM  
 A1    | 123     | 01/14/2016 10:30:35 AM |  01/14/2016 2:30:35 PM  
 B1    | 124     | 01/16/2016 10:30:35 PM |  01/18/2016  2:30:35 AM  
 C1    | 125     | 01/19/2016  9:30:20 AM |  01/19/2016  2:30:20 PM  
 D1    | 126     | 01/20/2016  3:15:25 AM |  01/21/2016  2:25:25 PM  

所需的SQL结果集:

A1 | 123 | 01/13/2016 | 00:29:30  
A1 | 123 | 01/14/2016 | 08:30:30  
B1 | 124 | 01/16/2016 | 01:29:25  
B1 | 124 | 01/17/2016 | 24:00:00  
B1 | 124 | 01/18/2016 | 02:30:35  
C1 | 125 | 01/19/2016 | 05:00:00  
D1 | 126 | 01/20/2016 | 20:44:35  

1 个答案:

答案 0 :(得分:0)

其中一种可能性:

with data as (
  select emp_id eid, task_id tid, task_start_date_time d1, task_stop_date_time d2, 
         trunc(task_stop_date_time)-trunc(task_start_date_time)+1 cnt from tasks),
rec(eid, tid, d1, d2, cnt, rn) as (
  select eid, tid, d1, d2, cnt, 1 from data
  union all 
  select eid, tid, d1, d2, cnt, rn+1 from rec where rn+1<=cnt),
res as (
  select eid, tid, rn, trunc(d1)+rn-1 dt, 
         least(d2, trunc(d1)+rn) - greatest(d1, trunc(d1)+rn-1) diff 
    from rec)
select eid, tid, dt, 
       to_char(trunc(diff*24), 'fm00')||':'||
       to_char(trunc(mod(diff*24*60, 60)), 'fm00')||':'||
       to_char(trunc(mod(diff*24*60*60, 60 )), 'fm00') diff
  from res order by eid, rn

步骤:

  • 1 - 子查询data - 此处我根据start_date和end_date之间的差异添加了包含天数的列cnt
  • 2 - 递归子查询rec - 这会为输入数据中的每一行生成所需的行数,
  • 3 - 子查询res - 添加了适当值的差异,这个差异以天为单位,
  • 4 - 上次查询,将diff从天数转换为hh:mm:ss格式。

运行此查询需要Oracle 11g。我将表命名为tasks,下面是示例数据和输出。

create table tasks (Emp_ID varchar2(2), Task_ID number(6), Task_start_date_time date, Task_stop_date_time date);
insert into tasks values ('A1', 123, timestamp '2016-01-13 23:30:30', timestamp '2016-01-14 00:30:30');
insert into tasks values ('B1', 124, timestamp '2016-01-16 22:30:35', timestamp '2016-01-18 02:30:35');
insert into tasks values ('C1', 125, timestamp '2016-01-19 09:30:20', timestamp '2016-01-19 14:30:20');
insert into tasks values ('D1', 126, timestamp '2016-01-20 03:15:25', timestamp '2016-01-21 14:25:25');

输出:

EID        TID DT       DIFF      
--- ---------- -------- -----------
A1         123 16/01/13 00:29:29    
A1         123 16/01/14 00:30:30    
B1         124 16/01/16 01:29:25    
B1         124 16/01/17 24:00:00    
B1         124 16/01/18 02:30:34    
C1         125 16/01/19 05:00:00    
D1         126 16/01/20 20:44:35    
D1         126 16/01/21 14:25:25 

更新:如果您要对值进行分组,就像在评论中提到的那样,您需要为每一天添加group by子句 - 请参阅子查询res和最终选择中的更改。< / p>

insert into tasks values ('A1', 123, 
                          timestamp '2016-01-14 10:30:35', 
                          timestamp '2016-01-14 14:30:35');

with data as (
  select emp_id eid, task_id tid, task_start_date_time d1, task_stop_date_time d2, 
         trunc(task_stop_date_time)-trunc(task_start_date_time)+1 cnt from tasks),
rec(eid, tid, d1, d2, cnt, rn) as (
  select eid, tid, d1, d2, cnt, 1 from data
  union all 
  select eid, tid, d1, d2, cnt, rn+1 from rec where rn+1<=cnt),
res as (
  select eid, tid, trunc(d1)+rn-1 dt, 
         sum(least(d2, trunc(d1)+rn) - greatest(d1, trunc(d1)+rn-1)) diff 
    from rec group by eid, tid, trunc(d1)+rn-1)
select eid, tid, dt, 
       to_char(trunc(diff*24), 'fm00')||':'||
       to_char(trunc(mod(diff*24*60, 60)), 'fm00')||':'||
       to_char(trunc(mod(diff*24*60*60, 60 )), 'fm00') diff
  from res order by eid, tid, dt

输出(更改在第2行:数据第一行30分30秒,第二行4小时):

EID        TID DT          DIFF
--- ---------- ----------- -----------
A1         123 2016-01-13  00:29:29
A1         123 2016-01-14  04:30:30
B1         124 2016-01-16  01:29:25
B1         124 2016-01-17  24:00:00
B1         124 2016-01-18  02:30:34
C1         125 2016-01-19  05:00:00
D1         126 2016-01-20  20:44:35
D1         126 2016-01-21  14:25:25