Reputation: 3845
PROBLEM
I'm still finding my feet with SQL and trying to calculate how long a certain user has been scanning items during their shift.
Each scan is timestamped generating a unique 9 digit sequence number (SEQ column) and date/time in the format 05-NOV-16 15:35:24
(THE_DATE column).
The person may be scanning for several hours, and what im trying to do is subtract the first timestamp they generated from the very last timestamp at the end of their shift.
So for example given this data sample:
+-----------+--------------------+--------+---------+---------+------------+-----------+
| 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 |
|+-----------+--------------------+--------+---------+---------+------------------------
DESIRED RESULT
I would like to subtract the timestamp in the first row for Mike Derry, from the last row on which he appears, row 5 in this case, so that i have an answer in hours (1.25).
the final result should be grouped by day and by user_id,first_name and last_name.
So far i have looked online and at the oracle documentation ,which led me to try using the LEAD function which seemed promising. It looks at the next rows to find the next timestamp where a userid appears next and then partitions by this userid to create a new column with that timestamp.
So the SQL looked like this
SELECT SEQ, THE_DATE,SCANID,LOCATN,USER_ID,LEAD(SYSDAT ) OVER (PARTITION BY USER_ID ORDER BY SYSDAT) AS NEXT_SCAN
FROM myTable...
However this is giving me incorrect results as it seems to double count the time difference. Im sure you SQL gurus have a more elegant way around this as i dont think this function suits this particular problem :)
So the final result im trying to achieve is:
+-----------+---------+------------+-----------+-----------+
| 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 |
+-----------+---------+------------+-----------+-----------+
Your help is much appreciated
Upvotes: 2
Views: 3543
Reputation:
Notes.... you shouldn't have redundant data (first name, last name) in this table, you should have a separate table just for that. It seems your hours are truncated and not rounded? (the rounding would give 1.26 in the first row).
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
Upvotes: 3
Reputation: 48177
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
Upvotes: 1