Oracle 11g - 用于计算多行之间时差的SQL

时间:2016-11-09 15:18:19

标签: sql oracle plsql oracle11g

问题

我还在用SQL查找我的脚并尝试计算某个用户在轮班期间扫描项目的时间。

每次扫描都带有时间戳,以格式05-NOV-16 15:35:24 THE_DATE 列)生成唯一的9位数序列号( SEQ 列)和日期/时间。< / p>

这个人可能正在扫描几个小时,而我想要做的是从他们轮班结束时的最后一个时间戳中减去他们生成的第一个时间戳。

例如,给出这个数据样本:

+-----------+--------------------+--------+---------+---------+------------+-----------+
|    SEQ    |      THE_DATE      | SCANID | LOCATN  | USER_ID | FIRST_NAME | LAST_NAME |
+-----------+--------------------+--------+---------+---------+------------+-----------+
| 103939758 | 05-NOV-16 14:36:22 | 194972 | DOOR 19 | AX9868  | Mike       | Derry     |
| 103939780 | 05-NOV-16 14:38:07 | 194972 | DOOR 19 | AX9868  | Mike       | Derry     |
| 103939792 | 05-NOV-16 14:39:24 | 194972 | DOOR 19 | AX9868  | Mike       | Derry     |
| 103940184 | 05-NOV-16 15:16:53 | 194972 | DOOR 19 | AX9868  | Mike       | Derry     |
| 103940185 | 05-NOV-16 15:51:41 | 194972 | DOOR 19 | AX9868  | Mike       | Derry     |
| 103940214 | 05-NOV-16 09:51:42 | 194993 | DOOR 16 | BC1910  | Tony       | McCann    |
| 103940215 | 05-NOV-16 15:19:06 | 194993 | DOOR 16 | BC1910  | Tony       | McCann    |
|+-----------+--------------------+--------+---------+---------+------------------------

期望的结果

我想在Mike Derry的第一行中减去时间戳,从他出现的最后一行开始,在这种情况下排第5行,这样我就可以在几小时内得到答案(1.25)。

最终结果应按天分组,并按user_id,first_name和last_name分组。

到目前为止,我已经在线查看了oracle文档,这使我尝试使用LEAD功能,这似乎很有希望。它查看下一行以查找下一个时间戳,其中userid出现在下一个时间段,然后由此用户ID分区以创建具有该时间戳的新列。

所以SQL看起来像这样

SELECT SEQ, THE_DATE,SCANID,LOCATN,USER_ID,LEAD(SYSDAT ) OVER (PARTITION BY USER_ID ORDER BY SYSDAT) AS NEXT_SCAN 
FROM myTable...

然而,这给了我不正确的结果,因为它似乎重复计算时差。我确定你的SQL专家有更优雅的方式,因为我不认为这个功能适合这个特殊的问题:)

因此,我想要实现的最终结果是:

+-----------+---------+------------+-----------+-----------+
| THE_DATE  | USER_ID | FIRST_NAME | LAST_NAME | TOTAL_HRS |
+-----------+---------+------------+-----------+-----------+
| 05-NOV-16 | AX9868  | Mike       | Derry     |      1.25 |
| 05-NOV-16 | BC1910  | Tony       | McCann    |      5.47 |
+-----------+---------+------------+-----------+-----------+

非常感谢您的帮助

2 个答案:

答案 0 :(得分:2)

注意....你不应该在这个表中有冗余数据(名字,姓氏),你应该有一个单独的表。看来你的小时数被截断而不是四舍五入? (四舍五入将在第一行给出1.26。)

with
     test_data ( seq, the_date, scanid, locatn, user_id, first_name, last_name ) as (
       select 103939758, to_date('05-NOV-16 14:36:22', 'dd-MON-yy hh24:mi:ss'), 194972, 'DOOR 19', 'AX9868', 'Mike', 'Derry'  from dual union all
       select 103939780, to_date('05-NOV-16 14:38:07', 'dd-MON-yy hh24:mi:ss'), 194972, 'DOOR 19', 'AX9868', 'Mike', 'Derry'  from dual union all
       select 103939792, to_date('05-NOV-16 14:39:24', 'dd-MON-yy hh24:mi:ss'), 194972, 'DOOR 19', 'AX9868', 'Mike', 'Derry'  from dual union all
       select 103940184, to_date('05-NOV-16 15:16:53', 'dd-MON-yy hh24:mi:ss'), 194972, 'DOOR 19', 'AX9868', 'Mike', 'Derry'  from dual union all
       select 103940185, to_date('05-NOV-16 15:51:41', 'dd-MON-yy hh24:mi:ss'), 194972, 'DOOR 19', 'AX9868', 'Mike', 'Derry'  from dual union all
       select 103940214, to_date('05-NOV-16 09:51:42', 'dd-MON-yy hh24:mi:ss'), 194993, 'DOOR 16', 'BC1910', 'Tony', 'McCann' from dual union all
       select 103940215, to_date('05-NOV-16 15:19:06', 'dd-MON-yy hh24:mi:ss'), 194993, 'DOOR 16', 'BC1910', 'Tony', 'McCann' from dual
     )
-- end of test data; solution (SQL query) begins below this line
select trunc(the_date) as the_date, user_id, first_name, last_name,
       trunc(24 * (max(the_date) - min(the_date)), 2) as total_hrs
from   test_data
group by trunc(the_date), user_id, first_name, last_name
;

THE_DATE  USER_ID FIRST_NAME LAST_NAME  TOTAL_HRS
--------- ------- ---------- --------- ----------
05-NOV-16 AX9868  Mike       Derry           1.25
05-NOV-16 BC1910  Tony       McCann          5.45

答案 1 :(得分:0)

SELECT TRUNC(THE_DATE) as THE_DATE, USER_ID, FIRST_NAME, LAST_NAME,
       MAX(THE_DATE) - MIN(THE_DATE) as TOTAL_HRS 
FROM yourTable
GROUP BY TRUNC(THE_DATE), USER_ID, FIRST_NAME, LAST_NAME