If your columns are timestamp
then the difference between them will be an interval. For the values you added as a comment:
select id, time_out - time_in as worked
from t42;
ID WORKED
---------- -----------
1 0 4:22:0.0
1 0 2:23:2.0
You want the total, but you can't directly sum
intervals. You could convert them to a numeric representation, sum them, and then convert them back:
select id, numtodsinterval(sum(
extract(day from dd) * (24 * 60 * 60)
+ extract(hour from dd) * (60 * 60)
+ extract(minute from dd) * 60
+ extract(second from dd)
), 'SECOND') as total_worked
from (
select id, time_out - time_in as dd
from t42
)
group by id;
ID TOTAL_WORKED
---------- ------------
1 0 6:45:2.0
You could also treat them as dates; it isn't entirely clear if you're using fractional seconds but for this kind of data it would seem like unnecessary precision. I'm not sure why you aren't using date
columns here (perhaps you just didn't realise that an Oracle date
column does contain the time down to the second anyway?). Anyway, you can cast them to dates:
select id,
sum(cast(time_out as date) - cast(time_in as date)) as total_days,
numtodsinterval(sum(cast(time_out as date) - cast(time_in as date)), 'DAY')
as total_interval,
to_char(trunc(sysdate)
+ sum(cast(time_out as date) - cast(time_in as date)), 'HH24:MI:SS')
as total_string
from t42
group by id;
ID TOTAL_DAYS TOTAL_INTERVAL TOTAL_STRING
---------- ---------- -------------- ------------
1 .281273148 0 6:45:2.0 06:45:02
The result of subtracting two dates is a number, where 1 would be a whole day. I've shown two ways to convert that to something more useful.
The to_char
version will only work if the total is less than a day though; if it might exceed 24 hours then you'd need to calculate it a different way:
select id,
trunc(dd * 24) as hh,
trunc((dd - (trunc(dd * 24)/24)) * 24 * 60) as mi,
trunc((dd - trunc(dd * 24 * 60)/(24 * 60)) * (24 * 60 * 60)) as ss
from (
select id,
sum(cast(time_out as date) - cast(time_in as date)) as dd
from t42
group by id
);
ID HH MI SS
---------- ---------- ---------- ----------
1 6 45 1
... and you can concatenate those into a string if you want (with lpad
to add leading zeros). It's odd that the 'seconds' value here is shown as 1, since (dd - trunc(dd * 24 * 60)/(24 * 60)) * (24 * 60 * 60)
is 2, and trunc(2)
is 2; not sure if there's a rounding error going on in their somewhere. If you use round
instead of trunc
in the final clasue then it works, but might give a slightly higher value than expected if you do have fractions of seconds.
SQL Fiddle, which doesn't show intervals in a very friendly format, unfortunately. That's with your sample, and another ID that does exceed 24 hours so you can see the difference; and with both round
and trunc
for the seconds in the last query.