Query that display all dates in a range - sql

I want to create a query that displays dates and counts. I want to display all dates within a range including dates with zero counts. I am looking for a way to do this WITHOUT using temp tables.
The output might look like:
Time Count
1/1/2017 01:00 AM 23
1/1/2017 02:00 AM 0
1/1/2017 03:00 AM 0
1/1/2017 04:00 AM 12

I was able to come up with an solutions that adds zero count rows. An example of the result set is below. You will see there are some duplicate DayOfWeekByHour values. I will need to figure out how to sum those up, but this is basically what I was looking for. See Example code link
DayOfWeekByHour, Count
100, 0
101, 0
102, 0
100, 23
201, 100
example of code
SELECT
TO_NUMBER(MOD(V,7)+1 || LPAD(MOD(V,24),2,'0')) as DayOfWeekByHour, 0
FROM (
SELECT 1 V FROM DUAL
) T
MODEL DIMENSION BY (ROWNUM R)
MEASURES (V)
RULES ITERATE (168) (
V[ITERATION_NUMBER] = CV(R) + 1
)
UNION
SELECT
TO_NUMBER(
TO_CHAR(
TO_DATE(
EXTRACT(MONTH FROM ve.CREATED_TIMESTAMP) || '/' ||
EXTRACT(DAY FROM ve.CREATED_TIMESTAMP) || '/' ||
EXTRACT(YEAR FROM ve.CREATED_TIMESTAMP) ,'MM/DD/YYYY'),'D'),'99') * 100 + TO_NUMBER(TO_CHAR(TO_DATE(
EXTRACT(MONTH FROM ve.CREATED_TIMESTAMP) || '/' ||
EXTRACT(DAY FROM ve.CREATED_TIMESTAMP) || '/' ||
EXTRACT(YEAR FROM ve.CREATED_TIMESTAMP) || ' ' ||
EXTRACT(HOUR FROM ve.CREATED_TIMESTAMP) || ':' ||
EXTRACT(MINUTE FROM ve.CREATED_TIMESTAMP)
,'MM/DD/YYYY HH24:MI'
)
,'HH24'
)
, '99') AS DayOfWeekByHour,
COUNT(*)
FROM
VIEWER.VIEWING_EVENT ve
WHERE
ve.CREATED_TIMESTAMP >= TO_TIMESTAMP('02-12-2016 00:00:00', 'dd-mm-yyyy hh24:mi:ss') AND
ve.CREATED_TIMESTAMP <= TO_TIMESTAMP('02-12-2017 00:00:00', 'dd-mm-yyyy hh24:mi:ss')
GROUP BY
TO_NUMBER(
TO_CHAR(
TO_DATE(
EXTRACT(MONTH FROM ve.CREATED_TIMESTAMP) || '/' ||
EXTRACT(DAY FROM ve.CREATED_TIMESTAMP) || '/' ||
EXTRACT(YEAR FROM ve.CREATED_TIMESTAMP) ,'MM/DD/YYYY'),'D'),'99') * 100 + TO_NUMBER(TO_CHAR(TO_DATE(
EXTRACT(MONTH FROM ve.CREATED_TIMESTAMP) || '/' ||
EXTRACT(DAY FROM ve.CREATED_TIMESTAMP) || '/' ||
EXTRACT(YEAR FROM ve.CREATED_TIMESTAMP) || ' ' ||
EXTRACT(HOUR FROM ve.CREATED_TIMESTAMP) || ':' ||
EXTRACT(MINUTE FROM ve.CREATED_TIMESTAMP)
,'MM/DD/YYYY HH24:MI'
)
,'HH24'
)
, '99')
ORDER BY
DayOfWeekByHour
;

Related

Converting decimals to [h]:mm in sql query

I need a requirement to convert decimal value to time in sql query like if input is 12.5 it should return 12h 30m, if input is 8.70 it should return 8h 42m.
You could use Oracle's numtodsinterval function to achieve this.
select numtodsinterval(to_number('12.5'), 'hour') from dual;
Returns 0 12:30:0.0
select numtodsinterval(to_number('8.70'), 'hour') from dual;
Returns 0 8:42:0.0
Maintain such conversation into a intermediate table and keep mapping to transform
Create a SP to convert and done
If the format literally needs to be like "12h 30m" and "8h 42m", then the following could work:
WITH sample_data AS
(
SELECT NUMTODSINTERVAL(to_number('12.5'), 'HOUR') ds_interval FROM dual UNION ALL
SELECT NUMTODSINTERVAL(to_number('8.70'), 'HOUR') ds_interval FROM dual UNION ALL
SELECT NUMTODSINTERVAL(to_number('122.25'), 'HOUR') ds_interval FROM dual
)
SELECT ( (EXTRACT(DAY FROM sample_data.ds_interval) * 24) +
EXTRACT(HOUR FROM sample_data.ds_interval) ) || 'h ' ||
EXTRACT(MINUTE FROM sample_data.ds_interval) || 'm ' output
FROM sample_data;
OUTPUT
--------
12h 30m
8h 42m
122h 15m
The format could be expanded to convert hours to days when # of hours >= 24:
WITH sample_data AS
(
SELECT NUMTODSINTERVAL(to_number('122.25'), 'HOUR') ds_interval FROM dual
)
SELECT EXTRACT(DAY FROM sample_data.ds_interval) || 'd ' ||
EXTRACT(HOUR FROM sample_data.ds_interval) || 'h ' ||
EXTRACT(MINUTE FROM sample_data.ds_interval) || 'm '
FROM sample_data;
OUTPUT
---------
5d 2h 15m

ORACLE SQL - How to check whether a time falls within a particular range?

There is a column 'DateTime' that displays the Date and Time in 'YYYY/MM/DD HH24:MI:SS' format.
I need to display only the rows that has time in a particular range(2AM - 6AM) regardless of the particular date.
I have a code that only displays the time range(2AM - 6AM) for the particular day. I need to display the rows that falls in the past 7 days with the time range 2AM-6AM.
SELECT *
FROM <table_name >
WHERE DateTime BETWEEN TO_DATE (
TO_CHAR (TRUNC (SYSDATE), 'DD-MM-YYYY')
|| ' '
|| '02:00:00',
'DD-MM-YYYY HH24:MI:SS')
AND TO_DATE (
TO_CHAR (TRUNC (SYSDATE), 'DD-MM-YYYY')
|| ' '
|| '06:00:00',
'DD-MM-YYYY HH24:MI:SS')
ORDER BY 1 DESC
SELECT *
FROM your_table
WHERE TO_CHAR( DateTime, 'HH24MMSS' ) BETWEEN '020000' AND '060000'
AND DateTime >= TRUNC( SYSDATE ) - INTERVAL '7' DAY
AND DateTime < TRUNC( SYSDATE ) + INTERVAL '1' DAY
or
SELECT *
FROM your_table
WHERE DateTime BETWEEN TRUNC( DateTime ) + INTERVAL '2' HOUR
AND TRUNC( DateTime ) + INTERVAL '6' HOUR
AND DateTime >= TRUNC( SYSDATE ) - INTERVAL '7' DAY
AND DateTime < TRUNC( SYSDATE ) + INTERVAL '1' DAY
You need two conditions for that: one for the hour being between 02 and 05, and one for the day being in the last seven days:
SELECT *
FROM <table_name>
WHERE to_char(DateTime, 'HH') BETWEEN '02' and '05' AND
DateTime BETWEEN SYSDATE - 7 AND SYSDATE
ORDER BY 1 DESC
In this case, I think the easiest way is string comparison:
WHERE SUBSTR(DateTime, 12, 2) BETWEEN '02' and '05'
Note: Between is inclusive so this should get everything up to 05:59:59.
SELECT *
FROM <table_name >
WHERE DateTime BETWEEN TO_DATE (
TO_CHAR (TRUNC (SYSDATE)-7, 'DD-MM-YYYY')
|| ' '
|| '02:00:00',
'DD-MM-YYYY HH24:MI:SS')
AND TO_DATE (
TO_CHAR (TRUNC (SYSDATE), 'DD-MM-YYYY')
|| ' '
|| '06:00:00',
'DD-MM-YYYY HH24:MI:SS')
select * from table_name where to_char(datetime,'HH24')
between '2' and '6' and to_char(datetime,'dd-mon-yy')
between to_char(sysdate,'dd-mon-yy') and to_char(sysdate-7,'dd-mon-yy');

Grouping SQL-Result by time does not work

I am trying to set up an SQL query in Firebird 2.5 in order to make a statistic about sales grouped by time.
My approach I followed up so far would be:
SELECT EXTRACT(WEEKDAY FROM ODR.ORDERDATE) AS S1, EXTRACT(HOUR FROM ODR.ORDERDATE) AS S2,
CASE
WHEN (EXTRACT(HOUR FROM ODR.ORDERDATE)) < 10 THEN
'0' || CAST(EXTRACT(HOUR FROM ODR.ORDERDATE) AS VARCHAR(2)) || ':00 - ' || '0' ||
CAST(EXTRACT(HOUR FROM ODR.ORDERDATE) AS VARCHAR(2)) || ':59 '
WHEN EXTRACT(HOUR FROM ODR.ORDERDATE) >= 10 THEN
CAST(EXTRACT(HOUR FROM ODR.ORDERDATE) AS VARCHAR(2)) || ':00 - ' ||
CAST(EXTRACT(HOUR FROM ODR.ORDERDATE) AS VARCHAR(2)) || ':59 '
END AS TINTERVAL,
COUNT(ODR.ID) AS ABSCOUNT
FROM ODR
GROUP BY S1,S2,TINTERVAL
ORDER BY S1,S2 ASC
The syntax of this query seems to be fine for SQL-Connection established by Firebird ODBC 2.5.
My question:
For hour=0 (<10) the query returns a result set which is not presented by the data given by the orders.
e.g. the result-set for this query might look like this:
S1 S2 TINTERVAL ABSCOUNT
0 0 00:00 - 00:59 30
0 1 01:00 - 01:59 2
I don't know how this query comes to its strange count in hour = 0.
This does not make any sense to me.

oracle sql compare times where > 1 on single work date

The not like operator is not suitable for comparing values where the number of values is > 1 on a single work date. In the example below the records in the first 2 rows are a match (bold=bold, italic=italic) and should NOT appear in the output. The issue is caused by the ‘not like’ operator looping.
i have simplified the code as follows:
SELECT e.EMP_NAME AS APS,
TO_CHAR (ws.WRKS_WORK_DATE, 'dd.mm.yyyy') AS Work_Date,
TO_CHAR ( (wd.WRKD_START_TIME), 'hh24:mi') AS Leave_Start_Time,
TO_CHAR ( (wd.WRKD_end_TIME), 'hh24:mi') AS Leave_End_Time,
TO_CHAR (sb.SHFTBRK_DEF_START, 'hh24:mi') AS shift_brk_Start,
TO_CHAR (sb.SHFTBRK_DEF_START + (sb.SHFTBRK_MINUTES + 1) * .000694,
'hh24:mi')
AS shift_brk_end
FROM work.WORK_SUMMARY ws,
work.employee e,
work.work_detail wd,
work.TIME_CODE tc,
work.shift s,
work.shift_break sb,
work.EMPLOYEE_SCHEDULE es
WHERE ws.emp_id = e.emp_id
AND wd.WRKD_MINUTES < s.SHFT_VAL1 ---sum workd minutes less than shift id actual shift minutes
AND ws.WRKS_WORK_DATE BETWEEN '09-Jul-2013' AND '09-Jul-2013'
AND wd.WRKS_ID = ws.WRKS_ID
AND tc.TCODE_name IN
('COMP', 'SL COMP PEN', 'ARB','LUC',
'CMF', 'MREP', 'WSSL', 'RL',
'CBK', 'JUR', 'LSL', 'LSLT',
'LWPNC', 'LWPS', 'LWPTC', 'LWPU',
'LWOP', 'ML', 'MLHP', 'NWPTC',
'PAT', 'PL', 'SD', 'MSP',
'SUS', 'SUSW', 'WIT', 'CMPA',
'ABC', 'ABN', 'BER', 'COM',
'COMWP', 'IS', 'EXL', 'LFI',
'MER', 'NCD', 'PCLC', 'PCLS',
'PSLC', 'PSLN', 'PSLW', 'PSWO',
'PSLP', 'PURL', 'STU', 'UA',
'GRTW')
AND wd.TCODE_ID = tc.TCODE_ID
AND ws.PAYGRP_ID IN ('10023')
AND ws.WRKS_AUTHORIZED = 'Y'
AND e.EMP_TERMINATION_DATE >= CURRENT_DATE
--and e.emp_name in('1100376801','1100590701')
AND ws.WRKS_WORK_DATE = es.WORK_DATE
AND ws.emp_id = es.emp_id
AND ws.shft_id = es.EMPSKD_ACT_SHIFT_ID
AND es.EMPSKD_ACT_SHIFT_ID = s.SHFT_ID
AND s.SHFT_ID = sb.SHFT_ID
AND ( ( TO_CHAR (sb.SHFTBRK_DEF_START, 'hh24:mi') <=
TO_CHAR ( (wd.WRKD_START_TIME), 'hh24:mi')
AND TO_CHAR (
sb.SHFTBRK_DEF_START
+ (sb.SHFTBRK_MINUTES + 1) * .000694,
'hh24:mi') >
TO_CHAR ( (wd.WRKD_START_TIME), 'hh24:mi'))
OR ( TO_CHAR (sb.SHFTBRK_DEF_START, 'hh24:mi') <
TO_CHAR ( (wd.WRKD_end_TIME), 'hh24:mi')
AND TO_CHAR (
sb.SHFTBRK_DEF_START
+ (sb.SHFTBRK_MINUTES + 1) * .000694,
'hh24:mi') > TO_CHAR ( (wd.WRKD_end_TIME), 'hh24:mi'))
OR ( TO_CHAR (sb.SHFTBRK_DEF_START, 'hh24:mi') >
TO_CHAR ( (wd.WRKD_START_TIME), 'hh24:mi')
AND TO_CHAR (
sb.SHFTBRK_DEF_START
+ (sb.SHFTBRK_MINUTES + 1) * .000694,
'hh24:mi') < TO_CHAR ( (wd.WRKD_end_TIME), 'hh24:mi'))
OR ( TO_CHAR (sb.SHFTBRK_DEF_START, 'hh24:mi') =
TO_CHAR ( (wd.WRKD_end_TIME), 'hh24:mi')
AND TO_CHAR (
sb.SHFTBRK_DEF_START
+ (sb.SHFTBRK_MINUTES + 1) * .000694,
'hh24:mi') = TO_CHAR ( (wd.WRKD_end_TIME), 'hh24:mi')))
GROUP BY e.EMP_NAME,
ws.WRKS_WORK_DATE,
wd.WRKD_end_TIME,
wd.WRKD_START_TIME,
sb.SHFTBRK_DEF_START,
TO_CHAR (sb.SHFTBRK_DEF_START + (sb.SHFTBRK_MINUTES + 1) * .000694,
'hh24:mi');
Result:
APS WORK_DATE LEAVE_START_TIME LEAVE_END_TIME SHIFT_BRK_START SHIFT_BRK_END
-------------------------------------------------------------------------------------
40151401 09.07.2013 10:00 13:00 10:30 11:00
40200001 09.07.2013 09:00 12:51 10:00 10:30
40447701 09.07.2013 09:30 14:15 10:00 10:30
40492101 09.07.2013 15:00 20:10 16:00 16:30
61037301 09.07.2013 10:35 14:15 11:00 11:30
64173401 09.07.2013 09:30 14:15 10:00 10:30
The issue is that i am expecting to see a record for employee 1100376801.
The reason I can't see the record is because the times for the missing record fall over midnight, i.e 00:51. How can i format the 'datetime' fields differently so that times over midnight are picked up, i.e. where the SHIFT_BRK_START and SHIFT_BRK_END times span or fall within the LEAVE_START_TIME and LEAVE_END_TIME.
Expected result: in addition to the results returned above i should also see the following record:
APS WORK_DATE LEAVE_START_TIME LEAVE_END_TIME SHIFT_BRK_START SHIFT_BRK_END
-------------------------------------------------------------------------------------
11003701 09.07.2013 20:00 **0:51** 19:30 19:45
RESOLUTION:
and
(
(to_date(to_char(wd.WRKD_START_TIME, 'dd.mm.yyyy') || '' || to_char(sb.SHFTBRK_DEF_START, 'hh24:mi'), 'dd.mm.yyyy hh24:mi') < (wd.WRKD_START_TIME) and
to_date(to_char(wd.WRKD_START_TIME, 'dd.mm.yyyy') || '' || to_char(sb.SHFTBRK_DEF_START + (sb.SHFTBRK_MINUTES+1)*.000694, 'hh24:mi'), 'dd.mm.yyyy hh24:mi') > (wd.WRKD_start_TIME))---1
OR(to_date(to_char(wd.WRKD_START_TIME, 'dd.mm.yyyy') || '' || to_char(sb.SHFTBRK_DEF_START, 'hh24:mi'), 'dd.mm.yyyy hh24:mi') =(wd.WRKD_START_TIME) and
to_date(to_char(wd.WRKD_START_TIME, 'dd.mm.yyyy') || '' || to_char(sb.SHFTBRK_DEF_START + (sb.SHFTBRK_MINUTES+1)*.000694, 'hh24:mi'), 'dd.mm.yyyy hh24:mi') = (wd.WRKD_end_TIME))--4
OR(to_date(to_char(wd.WRKD_START_TIME, 'dd.mm.yyyy') || '' || to_char(sb.SHFTBRK_DEF_START, 'hh24:mi'), 'dd.mm.yyyy hh24:mi') =(wd.WRKD_START_TIME) and
to_date(to_char(wd.WRKD_START_TIME, 'dd.mm.yyyy') || '' || to_char(sb.SHFTBRK_DEF_START + (sb.SHFTBRK_MINUTES+1)*.000694, 'hh24:mi'), 'dd.mm.yyyy hh24:mi') > (wd.WRKD_end_TIME))---5
OR(to_date(to_char(wd.WRKD_START_TIME, 'dd.mm.yyyy') || '' || to_char(sb.SHFTBRK_DEF_START, 'hh24:mi'), 'dd.mm.yyyy hh24:mi') =(wd.WRKD_START_TIME) and
to_date(to_char(wd.WRKD_START_TIME, 'dd.mm.yyyy') || '' || to_char(sb.SHFTBRK_DEF_START + (sb.SHFTBRK_MINUTES+1)*.000694, 'hh24:mi'), 'dd.mm.yyyy hh24:mi') <(wd.WRKD_end_TIME))---5
OR (to_date(to_char(wd.WRKD_START_TIME, 'dd.mm.yyyy') || '' || to_char(sb.SHFTBRK_DEF_START, 'hh24:mi'), 'dd.mm.yyyy hh24:mi') > (wd.WRKD_START_TIME) and
to_date(to_char(wd.WRKD_START_TIME, 'dd.mm.yyyy') || '' || to_char(sb.SHFTBRK_DEF_START + (sb.SHFTBRK_MINUTES+1)*.000694, 'hh24:mi'), 'dd.mm.yyyy hh24:mi') <= (wd.WRKD_end_TIME))---3
OR (to_date(to_char(wd.WRKD_START_TIME, 'dd.mm.yyyy') || '' || to_char(sb.SHFTBRK_DEF_START, 'hh24:mi'), 'dd.mm.yyyy hh24:mi') > (wd.WRKD_START_TIME) and
to_date(to_char(wd.WRKD_START_TIME, 'dd.mm.yyyy') || '' || to_char(sb.SHFTBRK_DEF_START, 'hh24:mi'), 'dd.mm.yyyy hh24:mi') < (wd.WRKD_end_TIME) and
to_date(to_char(wd.WRKD_START_TIME, 'dd.mm.yyyy') || '' || to_char(sb.SHFTBRK_DEF_START + (sb.SHFTBRK_MINUTES+1)*.000694, 'hh24:mi'), 'dd.mm.yyyy hh24:mi') > (wd.WRKD_end_TIME))---2
)
Its still not clear about your requirement and data
Here are some points to check:
check the two below queries with 'ALTER SESSION NLS_DATE_FORMAT = 'DD/MM/YYYY HH24:MI:SS';
(e.EMP_NAME || '_' || TO_CHAR(ws.WRKS_WORK_DATE,'dd.mm.yyyy') || '_' ||to_char(min(wd.WRKD_START_TIME), 'HH24:MI')|| '_' ||to_char(max(wd.WRKD_end_TIME), 'HH24:MI')) as test
(e.EMP_NAME || '_' || TO_CHAR(ws.WRKS_WORK_DATE,'dd.mm.yyyy') || '_' ||to_char(sb.SHFTBRK_DEF_START,'HH24:MI')|| '_' ||to_char(sb.SHFTBRK_DEF_START + (sb.SHFTBRK_MINUTES+1)*.000694, 'HH24:MI')) as test
The condition for outermost query might not work as you expected,
not like operator will fail as your inner query for the column test is different.
where a_emp_break.test not like b_shift_break.test
and a_emp_break.APS=b_shift_break.APS
and a_emp_break.Work_Date = b_shift_break.Work_Date
you didn't mention the date you needed anywhere.
updating
check with the below outer query again:
TO_CHAR (sb.SHFTBRK_DEF_START + (sb.SHFTBRK_MINUTES + 1) * .000694, 'hh24:mi') AS shift_brk_end
AND ws.WRKS_WORK_DATE BETWEEN '09-Jul-2013' AND '09-Jul-2013' check the above includes the desired ids.
check again with the conditions with the to_date() funcition that accurating with < and > symbols.
Thanks.

Get data in range using oracle

Please help me to solve this.
I have a table that contain users check in (checktype = I) and check out (checktype = 0) time everyday, and I would like to get the total amount of check in time per user which occur > 08:00 AM in a specific date range.
I am using the query below, but only handle one day per query not in a range, so I have to loop using javascript to get the amount of delay ( > 08:00 AM) per user for example from 01/06/2012 to 06/06/2012
Please help me to get the amount (count) check in time > 08:00 AM per user (ex: userid 708) from ex:01/06/2012 to 06/06/2012 in a single query.
with tt as
(
select TO_DATE('01/06/2012 08:00:00','dd/mm/yyyy hh24:mi:ss') date1 ,
checktime date2
from
checkinout
where
userid = '708' and
to_char(checktime,'dd/mm/yyyy') = '01/06/2012' and
checktype='I' -- checktype I is check in
) , t2 as
(
select numtodsinterval(date2 - date1,'day') dsinterval from tt
)
select extract(hour from dsinterval) || ' hours ' ||
extract(minute from dsinterval) || ' minutes ' ||
round(extract(second from dsinterval)) || ' seconds' late from t2
I assume you wanted to get how many hours late (i.e. after 08:00) the checkins have been done:
with t2 as (
select userid
,numtodsinterval(sum(checktime - (trunc(checktime)+8/24)),'day') dsinterval
,count(1) cnt
from checkinout
where userid='708'
and checktime > trunc(checktime)+8/24
and trunc(checktime) between to_date('01/06/2012','DD/MM/YYYY') and to_date('06/06/2012','DD/MM/YYYY')
and checktype = 'I'
group by userid
)
select extract(hour from dsinterval) || ' hours ' ||
extract(minute from dsinterval) || ' minutes ' ||
round(extract(second from dsinterval)) || ' seconds' late
,cnt
from t2;
See http://sqlfiddle.com/#!4/c4670/11 for my test case.
edit: added column "cnt" to show how many times
Consider the following example on base of this you can write your own logic
WITH tbl AS
(SELECT SYSDATE dt
FROM DUAL
UNION
SELECT SYSDATE + (1 + (10 / 1440))
FROM DUAL
UNION
SELECT SYSDATE + (2 + (12 / 1440))
FROM DUAL
UNION
SELECT SYSDATE + (3 + (13 / 1440))
FROM DUAL
UNION
SELECT SYSDATE + (6 + (15 / 1440))
FROM DUAL
UNION
SELECT SYSDATE + (8 + (18 / 1440))
FROM DUAL)
SELECT EXTRACT (HOUR FROM dsinterval)
|| ' hours '
|| EXTRACT (MINUTE FROM dsinterval)
|| ' minutes '
|| ROUND (EXTRACT (SECOND FROM dsinterval))
|| ' seconds' late
FROM (SELECT NUMTODSINTERVAL (dt1 - dt2, 'day') dsinterval
FROM (SELECT TO_DATE (TO_CHAR (dt, 'DD/MM/YYYY') || ' 08:00:00',
'DD/MM/YYYY HH24:MI:SS'
) dt1,
TO_DATE (TO_CHAR (dt, 'DD/MM/YYYY HH24:MI:SS'),
'DD/MM/YYYY HH24:MI:SS'
) dt2
FROM tbl
WHERE dt BETWEEN SYSDATE + 2 AND SYSDATE + 5))
As per code you can write like
SELECT EXTRACT (HOUR FROM dsinterval)
|| ' hours '
|| EXTRACT (MINUTE FROM dsinterval)
|| ' minutes '
|| ROUND (EXTRACT (SECOND FROM dsinterval))
|| ' seconds' late
FROM (SELECT NUMTODSINTERVAL (dt1 - dt2, 'day') dsinterval
FROM (SELECT TO_DATE (TO_CHAR (checktime , 'DD/MM/YYYY') || ' 08:00:00',
'DD/MM/YYYY HH24:MI:SS'
) dt1,
TO_DATE (checktime, 'DD/MM/YYYY HH24:MI:SS') dt2
FROM checkinout
WHERE checktime BETWEEN start_date AND end_date
AND checktype='I'))