ORA-01722: invalid number on subquery - sql

Hi i'm trying to execute my query and unfortunately trows me wih error of ORA-01722: invalid number
SELECT L.NEVENTLOGIDN, LPAD (nuserid, 6, '0') nuserid, u.susername,
TO_CHAR (TO_DATE ('1970-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS') + ( (ndatetime) / (60 * 60 * 24)), 'YYYY-MM-DD HH24:MI:SS')
date_time, l.nreaderidn, r.sname,
CASE WHEN l.nreaderidn IN (SELECT GETREADERSBYFUNC('OUT', 'LOCKER') devices FROM dual ) THEN 'O'
WHEN l.nreaderidn IN (SELECT GETREADERSBYFUNC('IN', 'LOCKER') devices FROM dual ) THEN 'I' END logtype
FROM TB_EVENT_LOG l, TB_READER r, TB_USER u
WHERE
l.nreaderidn IN ( SELECT GETREADERSBYDESC('LOCKER') devices FROM dual)
AND NDATETIME >= ((TO_DATE ('2020-01-27' || ' 12:00:00 AM', 'YYYY-MM-DD HH:MI:SS AM') ) - TO_DATE ('1970-01-01 12:00:00 AM', 'YYYY-MM-DD HH:MI:SS AM')) * 24 * 60 * 60
AND ndatetime <= ((TO_DATE ('2020-01-28' || ' 12:00:00 PM', 'YYYY-MM-DD HH:MI:SS PM') ) - TO_DATE ('1970-01-01 12:00:00 AM', 'YYYY-MM-DD HH:MI:SS AM')) * 24 * 60 * 60
AND l.nuserid = u.suserid
AND l.nreaderidn = r.nreaderidn
ORDER BY 2, 4
I think the reason of error is this below.
1
CASE WHEN l.nreaderidn IN (SELECT GETREADERSBYFUNC('OUT', 'LOCKER') devices FROM dual ) THEN 'O'
sample data of GetReaderbyfunc
'544381428','544381436','544381433','544381424','544381043'
2
WHEN l.nreaderidn IN (SELECT GETREADERSBYFUNC('IN', 'LOCKER') devices FROM dual ) THEN 'I' END logtype
3
WHERE
l.nreaderidn IN ( SELECT GETREADERSBYDESC('LOCKER') devices FROM dual)
SELECT GETREADERSBYFUNC('OUT', 'LOCKER') devices FROM dual
result is below
'544381428','544381436','544381433','544381424','544381043'
because the nreaderidn is a number type but when i put the result of it like bellow it is working
SELECT GETREADERSBYDESC('LOCKER') devices FROM dual
result is bellow
'544381050','544381441','544381428','544381436','544381431','544381064','544381433','544381435','544381424','544381043'
WHERE
l.nreaderidn IN ( '544381428','544381436','544381433','544381424','544381043')
functions
getreadersbyfunc (p_func VARCHAR2, p_desc VARCHAR2)
RETURN VARCHAR2
IS
retVal VARCHAR2(1024);
BEGIN
for cur_rec in (SELECT nreaderidn FROM tb_reader where sdescription = p_desc and upper(sname) like '%' || upper(p_func) || '%')
loop
if retVal is NULL then
retVal := '''' || cur_rec.nreaderidn || '''';
else
retVal := retVal || ',''' || cur_rec.nreaderidn || '''';
end if;
end loop;
return retVal;
EXCEPTION
WHEN NO_DATA_FOUND THEN
NULL;
WHEN OTHERS THEN
RAISE;
getreadersbydesc (p_description VARCHAR2)
RETURN VARCHAR2
IS
retVal VARCHAR2(1024);
BEGIN
for cur_rec in (SELECT nreaderidn FROM tb_reader where sdescription = p_description)
loop
if retVal is NULL then
retVal := '''' || cur_rec.nreaderidn || '''';
else
retVal := retVal || ',''' || cur_rec.nreaderidn || '''';
end if;
end loop;
return retVal;
EXCEPTION
WHEN NO_DATA_FOUND THEN
NULL;
WHEN OTHERS THEN
RAISE;
END;
I'm not allowed to change the data type of nreaderidn and to modify the oracle function.
Is There a way to solve this?
Thank you in advance

Your function returns a comma separated list of numbers, which needs to be split.
Try th
Eg:
SELECT
regexp_substr(GETREADERSBYFUNC('OUT', 'LOCKER'), '[^,]+', 1, level)
FROM dual
connect by
regexp_substr(GETREADERSBYFUNC('OUT', 'LOCKER'), '[^,]+', 1, level) is not null
Your query would then look like:
SELECT L.NEVENTLOGIDN, LPAD (nuserid, 6, '0') nuserid, u.susername,
TO_CHAR (TO_DATE ('1970-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS') + ( (ndatetime) / (60 * 60 * 24)), 'YYYY-MM-DD HH24:MI:SS')
date_time, l.nreaderidn, r.sname,
CASE WHEN l.nreaderidn IN (SELECT
regexp_substr(GETREADERSBYFUNC('OUT', 'LOCKER'), '[^,]+', 1, level) FROM dual
connect by regexp_substr(GETREADERSBYFUNC('OUT', 'LOCKER'), '[^,]+', 1, level) is not null ) THEN 'O'
WHEN l.nreaderidn IN (SELECT
regexp_substr(GETREADERSBYFUNC('IN', 'LOCKER'), '[^,]+', 1, level) FROM dual
connect by regexp_substr(GETREADERSBYFUNC('IN', 'LOCKER'), '[^,]+', 1, level) is not null) THEN 'I' END logtype
FROM TB_EVENT_LOG l, TB_READER r, TB_USER u
WHERE
l.nreaderidn IN ( SELECT
regexp_substr(GETREADERSBYFUNC('LOCKER'), '[^,]+', 1, level) FROM dual
connect by regexp_substr(GETREADERSBYFUNC('LOCKER'), '[^,]+', 1, level) is not null)
AND NDATETIME >= ((TO_DATE ('2020-01-27' || ' 12:00:00 AM', 'YYYY-MM-DD HH:MI:SS AM') ) - TO_DATE ('1970-01-01 12:00:00 AM', 'YYYY-MM-DD HH:MI:SS AM')) * 24 * 60 * 60
AND ndatetime <= ((TO_DATE ('2020-01-28' || ' 12:00:00 PM', 'YYYY-MM-DD HH:MI:SS PM') ) - TO_DATE ('1970-01-01 12:00:00 AM', 'YYYY-MM-DD HH:MI:SS AM')) * 24 * 60 * 60
AND l.nuserid = u.suserid
AND l.nreaderidn = r.nreaderidn
ORDER BY 2, 4

This will not give you an error:
SELECT *
from TB_READER l
where cast(l.nreaderidn as varchar2(1024)) in (select GETREADERSBYDESC('LOCKER') devices FROM dual)
Just use the cast of the nreaderidn column.
But also be aware that you will search a varchar like for example '2' in the string(not an series of characters but one string) '1','2','3' so this will not retun any results.
Here is also a small example where you can see the errir being produced without a cast and solved when the cast is added:
https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=776ecd951aff56500938ac064b34788c

Related

MOD command calling functions

I have two functions, which are working fine. I want to use the MOD or decode command to call the functions with different options but I can't seem to get the code below to work.
Below is my test CASE. Any help would be greatly appreciated. Thanks in advance for your time and expertise.
ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'DD-MON-YYYY HH24:MI:SS.FF';
ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MON-YYYY HH24:MI:SS'
CREATE OR REPLACE FUNCTION random_timestamp(
p_from IN TIMESTAMP,
p_to IN TIMESTAMP,
p_fraction IN VARCHAR2 DEFAULT 'Y'
) RETURN TIMESTAMP
IS
return_val_y TIMESTAMP := p_from + dbms_random.value () * (p_to - p_from + INTERVAL '1' DAY);
return_val_n TIMESTAMP (0) := return_val_y;
BEGIN
RETURN CASE
WHEN UPPER (SUBSTR (p_fraction, 1, 1)) = 'Y'
THEN return_val_y
ELSE return_val_N
END;
END random_timestamp;
/
CREATE OR REPLACE FUNCTION random_interval(
p_min IN NUMBER,
p_max IN NUMBER,
p_duration IN VARCHAR2,
p_fraction IN VARCHAR2 DEFAULT 'Y'
) RETURN INTERVAL DAY TO SECOND
IS
return_val_y INTERVAL DAY TO SECOND := NUMTODSINTERVAL(DBMS_RANDOM.VALUE(p_min, p_max), p_duration);
return_val_n INTERVAL DAY TO SECOND :=
( EXTRACT(DAY FROM return_val_y) * 24 * 60 * 60
+ EXTRACT(HOUR FROM return_val_y) * 60 * 60
+ EXTRACT(MINUTE FROM return_val_y) * 60
+ FLOOR(EXTRACT(SECOND FROM return_val_y))
) * INTERVAL '1' SECOND;
BEGIN
RETURN CASE
WHEN UPPER (SUBSTR (p_fraction, 1, 1)) = 'Y'
THEN return_val_y
ELSE return_val_N
END;
END random_interval;
/
/* can't get this to work */
SELECT
CASE MOD(LEVEL, 2)
WHEN 0
THEN
random_timestamp(TIMESTAMP '2022-04-01 00:00:00', TIMESTAMP '2022-04-30 00:00:00', 'Y') as ts,
random_interval(1, 10, 'HOUR', 'Y') as invr
ELSE
random_timestamp(TIMESTAMP '2022-04-01 00:00:00', TIMESTAMP '2022-04-30 00:00:00', 'N') as ts,
random_interval(1, 10, 'HOUR', 'N') as invr
END
FROM dual
CONNECT BY level <= 10;
A CASE expression returns a single expression; not multiple expressions. If you want multiple expressions then move the CASE from wrapping both of them (which is wrong) to inside each of the function calls:
SELECT random_timestamp(
TIMESTAMP '2022-04-01 00:00:00',
TIMESTAMP '2022-04-30 00:00:00',
CASE MOD(LEVEL, 2) WHEN 0 THEN 'Y' ELSE 'N' END
) as ts,
random_interval(
1,
10,
'HOUR',
CASE MOD(LEVEL, 2) WHEN 0 THEN 'Y' ELSE 'N' END
) as invr
FROM dual
CONNECT BY level <= 10;
fiddle

How can I use columns value from nested select in main select?

I'm trying to execute this SQL in Oracle:
select z.*
from (select (CASE
WHEN trunc(to_date('01.02.2015', 'DD.MM.YY'), 'MM') =
to_date('01.02.2015', 'DD.MM.YY') THEN
trunc(ADD_MONTHS(sysdate, -1), 'MM')
ELSE
trunc(sysdate - 1)
END) as sd,
trunc(sysdate) ed
from dual) t,
(SELECT *
FROM table(SOMEOWNERUSER.SOMEPACKAGE.getPipelinedTable(to_char(t.sd,
'dd.mm.yyyy'),
to_char(t.ed,
'dd.mm.yyyy')))) z
But I get error ORA-00904: "T"."SD": invalid identifier. What am I doing wrong?
You just need to directly reference the table() in the same level join as the t subquery:
create type dt_type as object (dt date);
/
create type dt_tab as table of dt_type;
/
create or replace function getpipelinedtable (p_sd date, p_ed date)
return dt_tab
as
l_tab dt_tab := dt_tab();
begin
for i in 1 .. (p_ed - p_sd) + 1
loop
l_tab.extend;
l_tab(l_tab.last) := dt_type(p_sd -1 + i);
end loop;
return l_tab;
end getpipelinedtable;
/
SELECT z.*
FROM (SELECT (CASE WHEN TRUNC (TO_DATE ('01.02.2015', 'DD.MM.YY'), 'MM') = TO_DATE ('01.02.2015', 'DD.MM.YY')
THEN TRUNC (ADD_MONTHS (SYSDATE, -1), 'MM')
ELSE TRUNC (SYSDATE - 1)
END) AS sd,
TRUNC (SYSDATE) ed
FROM DUAL) t,
TABLE ( getpipelinedtable (t.sd, t.ed) ) z;
DT
----------
01/01/2015
02/01/2015
03/01/2015
04/01/2015
05/01/2015
<snip>
06/02/2015
07/02/2015
08/02/2015
09/02/2015
drop function getpipelinedtable;
drop type dt_tab;
drop type dt_type;

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'))

oracle query help using NVL similar function to set default

How do I rewrite this oracle query, in the case I have no rows returned and want to hardcode a default value of '0' for a count and the sysdate information?
My query now will give me this if there is no data:
1* SELECT count(*) as MYCNT, timestamp FROM TESTDATA WHERE timestamp = to_char(sysdate-2, 'yyyymmdd') || '0000' group by timestamp
SQL> /
no rows selected
Here, I tried NVL, but not getting expected output:
1* select nvl(count(*), 0) as MYCNT, to_char(sysdate-2, 'yyyymmdd') || '0000' from TESTDATA WHERE timestamp = to_char(sysdate-2, 'yyyymmdd') || '0000' group by timestamp
SQL> /
no rows selected
Want to see something like this:
MYCNT TIMESTMP
----- --------
0 201107250000
The group by is preventing this from just working by defult.
select count(*) , to_char(sysdate-2, 'yyyymmdd') || '0000' as timestamp
from dual where 1=0
You can see this is the case by comparing the output to:
select count(*) , to_char(sysdate-2, 'yyyymmdd') || '0000' as timestamp
from dual where 1=0
group by to_char(sysdate-2, 'yyyymmdd') || '0000'
Second version returns blank, first version returns 0 and the timestamp
try
SELECT 0, to_char(sysdate-2, 'yyyymmdd') || '0000' FROM DUAL WHERE 0 =
(SELECT count(*) FROM TESTDATA WHERE timestamp = to_char(sysdate-2, 'yyyymmdd') || '0000')
UNION
SELECT count(*) as MYCNT, timestamp FROM TESTDATA WHERE timestamp = to_char(sysdate-2, 'yyyymmdd') || '0000' group by timestamp
this return the real data if it is present and if not the default
Try this:
SELECT count(*) as MYCNT, timestamp
FROM TESTDATA
WHERE timestamp = to_char(sysdate-2, 'yyyymmdd') || '0000'
GROUP BY timestamp
UNION
SELECT 0, '201107250000'
FROM dual