using multiple dates in the IN clause of a sql statement - sql

I have function which returns a list of comma seperated dates(e.g. 'Dec 24, 2011','Dec 26, 2011','Dec 18, 2011','Dec 27, 2011'.
I am receiving this as a single string.
I want to use this string to build a select query where I want to use the string in the IN clause.
e.g.
select *
from wfdisplaymgmt
where programstartdate IN(TO_DATE('Dec 26, 2011','MON dd, yyyy'))
Since I am getting a multiple dates I would like to use all the dates in my statement.how can I write the sql query which inlcudes multiple dates.Please help.
Update:
One more thing is I have window with a textbox and a button on clicking the button a sql query is executed.The query returns a distinct number of column values which has an option of selecting each of those values.when the user selects the required values ,the values are copied to the text box(e.g.'Dec 24, 2011','Dec 26, 2011','Dec 18, 2011','Dec 27, 2011' if I have selected four dates).Now the String I want to use this string in a sql statement where I select all the columns of the table based on the selected dates found in the string i.e.values found in the text box.
'Mon DD,YYYY' is the date format returned in the string.
I want a query similar to
select *
from wfdisplaymgmt
where programstartdate IN(the date values coming from the text box)
how do I do this?

Change your PLSQL function to return a user-defined data type TABLE OF DATE (or TIMESTAMP) and use IN to match values.
Note you will probably need to TRUNC the date values in order to match them. Noon != Midnight!
The following code illustrates the approach.
WHENEVER SQLERROR EXIT FAIL ROLLBACK
set echo on
COLUMN programstartdate FORMAT A45
column column_value format a45
set serveroutput on
<<REINITIALIZE>>
BEGIN
FOR DOIT IN (SELECT 'DROP TABLE ' || TABLE_NAME AS CMD FROM USER_TABLES WHERE TABLE_NAME = 'WFDISPLAYMGMT')
LOOP
EXECUTE IMMEDIATE DOIT.CMD;
DBMS_OUTPUT.PUT_LINE ('Dropped test table via command: ' || doit.CMD);
end loop;
dbms_random.seed('This doesn''t quite feel random until I add the microseconds ' || to_char (systimestamp, 'D FF9'));
END REINITIALIZE;
/
CREATE OR REPLACE TYPE DATELIST AS TABLE OF date;
/
show errors type datelist
CREATE OR REPLACE FUNCTION GETDATES (HOWMANY IN NUMBER) RETURN DATELIST
IS
TO_RETURN DATELIST := datelist();
BEGIN
for stepback in 1 .. howmany
loop
to_return.extend();
TO_RETURN(stepback) := trunc(sysdate - stepback);
end loop;
RETURN TO_RETURN;
END GETDATES;
/
show errors function getdates;
select * from table(cast (getdates (7) as datelist));
create table WFDISPLAYMGMT
as
select
TRUNC(dbms_random.value (50, 10000)) as bogus_id,
column_value as programstartdate
from (select rownum as row_no, column_value from table(cast (getdates (30) as datelist)))
where abs (mod (row_no, 3)) = 1
;
commit;
select count (*) as generated_rows from WFDISPLAYMGMT;
select *
from WFDISPLAYMGMT
where programstartdate in (select * from table (cast (getdates (15) as datelist)));

Here's a slightly convoluted way to do this in SQL only. The below is a sample you can run immediately in your instance to check it out:
select to_date(replace(VAL, '''', ''), 'Mon dd, yyyy') as NEWDATE
from (with TST1 as
(select length(DTXT) - length(translate(DTXT, REPLVAL || VALSEP, REPLVAL)) + 1 as NUMVAL
,VALSEP
,DTXT || VALSEP as DTXT
from (select replace('''Dec 24, 2011'',''Dec 26, 2011'',''Dec 18, 2011'',''Dec 27, 2011'''
,''','''
,'''|''')
as DTXT
,'|' as VALSEP
,chr(0) as REPLVAL
from dual))
select substr(TST1.DTXT
,decode(rownum, 1, 1, instr(TST1.DTXT, VALSEP, 1, rownum - 1) + length(VALSEP))
, instr(TST1.DTXT, VALSEP, 1, rownum)
- decode(rownum, 1, 0, instr(TST1.DTXT, VALSEP, 1, rownum - 1))
- 1)
as VAL
from TST1
connect by level <= TST1.NUMVAL)
What it does is take your comma-separated dates and converts them into individual records that can then be cast to date type. In your scenario you can replace the sub-query that selects from dual with your function, e.g.:
select *
from wfdisplaymgmt
where programstartdate IN (
select to_date(replace(VAL, '''', ''), 'Mon dd, yyyy') as NEWDATE
...
select replace(myfunctioncall()
,''','''
,'''|''')
as DTXT
,'|' as VALSEP
,chr(0) as REPLVAL
from dual
...
What I've done here is replace the comma separators with pipe separators as you have a comma appearing in the date format. Also, I have appended the pipe separator to the end of the text so that the last value is included. If you need further details on what each bit does then add a comment.

you can use the EXECUTE() function to execute a string as a sql statement, that would work, or else you just can split the string of dates up into a table variable and then use in on the table variable. Both work, I think the table variable is probably a better solution.

Assuming oracle and I'm rusty at best for that techology
select *
from wfdisplaymgmt
where instr(your_function_that_delivers_dates()
, TO_CHAR(programstartdate,'MON DD, YYYY')) > 0
Don't expect blasting performance on large tables because the queryplan is not going to use any index, instead it will do a full-table scan
Based on info found here

Consider creating a new function (or replacing the old) that returns you a table (array) of data instead of a csv list in single string. It will be much easier to actually use the function in a meaningful way:
-- Create types
CREATE TYPE t_tf_row AS OBJECT (
id NUMBER,
dte date
);
/
CREATE TYPE t_tf_tab IS TABLE OF t_tf_row;
/
-- Build the table function itself.
CREATE OR REPLACE FUNCTION get_tab_tf (p_rows IN NUMBER) RETURN t_tf_tab AS
l_tab t_tf_tab := t_tf_tab();
l_dte date;
BEGIN
-- create rows
FOR i IN 1 .. p_rows LOOP
l_dte := sysdate - i;
l_tab.extend;
l_tab(l_tab.last) := t_tf_row(i, l_dte);
END LOOP;
RETURN l_tab;
END;
/
-- test new function, selecting 20 dates
select * from MY_TABLE
where MY_DATE in (select dte from table(get_tab_tf(20)));
Of course, in your version of the function create the dates the way you need them. Also note that you could do a pipelined version as well, but I assume the list of dates is reasonable in length.

Related

Converting decimal to Date

I have a column with dates formatted as decimals, for example: 20,210,830.
I want to convert this number to date format as 08/30/2021
I have tried to use convert and the database shoots me an error that convert is not a valid function. Cast seems to work but, only returns a null value every time.
This statement will validate:
SELECT CAST(CAST(CONTCLMPDTE AS VARCHAR(8)) AS DATE)
FROM CMSFIL.JCTDSC AS COMPLDATE
This statement works but, just outputs null. For background I am querying from a Db2 database.
My ultimate goal is to use this converted date to grab the difference from the current day.
Such as
DAY(CURRENT_DATE) - DAY(COMPLDATE)
Converting it to a date, you cqan do it like this
CREATE TABLE JCTDSC (
CONTCLMPDTE varchar(10)
);
INSERT INTO JCTDSC VALUES ('20,220,830')
SELECT date(to_date(REPLACE(CONTCLMPDTE,',',''),'YYYYMMDD')) FROM JCTDSC AS COMPLDATE
1
2022-08-30
fiddle
So after a long couple days and almost pulling my hair out, here is what worked for me.
SELECT date(substr(CONTCLMPDTE,1,4)||'-'||substr(CONTCLMPDTE,5,2)||'-'||substr(CONTCLMPDTE,7,2)) FROM JCTDSC WHERE COMPANYNUMBER={Company Number} AND JOBNUMBER={Job Number} LIMIT 1
This formatted from yyyymmdd to mm/dd/yyyy. It also worked for finding the days between current_date and CONTCLMPDTE using this code.
DAYS(CURRENT_DATE) - DAYS({COntract Compl Date Formatted})
Thank you all for your help!
You probably get an error because you have some INT / DECIMAL value which can't be converted to a date using this pattern.
The solution is to create some "safe" conversion function "eating" errors like below.
CREATE FUNCTION DATE_SAFE (P_DT INT)
RETURNS DATE
CONTAINS SQL
NO EXTERNAL ACTION
DETERMINISTIC
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
RETURN CAST (NULL AS DATE);
END;
RETURN DATE (TO_DATE (CAST (P_DT AS CHAR (8)), 'YYYYMMDD'));
END
Usage:
SELECT
CONTCLMPDTE
--, DATE (TO_DATE (CAST (CONTCLMPDTE AS CHAR (8)), 'YYYYMMDD'))
, DATE_SAFE (CONTCLMPDTE)
FROM (VALUES 0, 20220830) T (CONTCLMPDTE)
The function returns NULL if the corresponding INT can't be converted to a DATE, and no error is thrown as in case, when you uncomment the commented out line with built-in functions only.
The value just need to be converted into a string with a date format. Then you can use the date() function to convert to date.
create table qtemp/dec_vals (
col1 decimal(8,0) );
insert into qtemp/dec_vals
values (20200830), (20200831), (20200901), (20200902), (20200903), (20200904), (20200905), (20200906);
select date(substr(char(col1), 5, 2) || '/' || substr(char(col1), 7, 2) || '/' || substr(char(col1), 1, 4)) from qtemp/dec_vals;

Receiving ORA-01843: not a valid month error while retrieving data between two dates

I have a column in oracle database table which is Varchar2. In this column I am storing date line 29-1-2021 or 28-12-2020. I want to retrieve data from below query between two dates then I am getting error of Invalid month. How can I resolve this issue ?
SELECT Line_Stop_Id, Function_name, Product_family, line_description, Reason_Category, Reason_detail,
Product_item, product_description, request_raised_date, request_raised_time, cm.EMP_NAME as raised_by, Lse.User_Closer_Description,
Cm1.Emp_Name as Closer_User, Lse.User_Closer_Date, Lse.Final_Closer_Description, Lse.Final_Closer_Date, Lse.Final_Closer_Time,
Cm2.Emp_Name as Final_Closer, Lse.Resource_Effected ,
ROUND(24*(sysdate - to_date(Request_Raised_Date
||' '
||request_raised_time, 'DD-Mon-RR HH24:MI:SS'))) AS TAT
FROM Xx_Lsp_Linestoppage_Entry lse
Left join Emp_Master cm ON Lse.Raised_By = Cm.Emp_No
Left join Emp_Master cm1 ON Lse.Closer_User = Cm1.Emp_No
Left join Emp_Master cm2 ON Lse.Final_Closed_By = Cm2.Emp_No
where TO_DATE(Lse.Request_Raised_Date, 'DD-Mon-RR') Between TO_DATE('01-Jan-21', 'DD-Mon-RR') and TO_DATE('29-Jan-21', 'DD-Mon-RR');
You should check the validity of your date values stored as strings before a conversion and do a cleanup of them (of fix them).
This can be done via, for example, cursor in PL/SQL block (or wrapped in function to export query results or filter by its value):
declare
l_date date;
begin
for r in (
select distinct
request_raised_time
from Xx_Lsp_Linestoppage_Entry
/*To reduce rows in cursor*/
where not regexp_like('^\d{2}-\d{2}-\d{4}')
) loop
begin
l_date := to_date(r.q, 'dd-mm-yyyy');
exception
when others then dbms_output.put_line('Invalid date: ' || r.q);
end;
end loop;
end;
/
db<>fiddle here
Note, that you need to quote dashes inside format to make it exact, because Oracle treats unquoted dash as any symbol from quite wide set of delimiters. So it will process 01/12/2020 as date '2020-12-01', not as invalid date.
select to_date('01/12/2021', 'dd-mm-yyyy') as dt from dual;
DT
--------------------
2021-12-01T00:00:00Z
Elapsed: 00:00:00.002
1 rows selected.
select to_date('01-12-2021', 'dd-mm-yyyy') as dt from dual;
DT
--------------------
2021-12-01T00:00:00Z
Elapsed: 00:00:00.002
1 rows selected.
select to_date('01$12$2021', 'dd-mm-yyyy') as dt from dual;
DT
--------------------
2021-12-01T00:00:00Z
Elapsed: 00:00:00.002
1 rows selected.
You are storing the date in the format 29-1-2020 (dd-mm-yyyy) so use this format in the to_Date
replace
DD-Mon-RR
with
dd-mm-yyyy
Probably being the Lse.Request_Raised_Date field of type varchar2 it contains more information than you need for your query.
I think the best way is to select a string that only identifies the part necessary for the identification of the date using the function:
substr(string , string start from , string lenght )
This is an example:
select to_date(substr('29-01-2021 23:01:55',1,10),'DD-MM-YYYY') from dual;
TO_DATE (SU
----------
29-01-2021
instead of my string '29 -01-2021 23:01:55 ' enter field Lse.Request_Raised_Date
You can use on conversion error:
to_date(Request_Raised_Date || ' ' || request_raised_time
default null on conversion error, 'DD-Mon-YYYY HH24:MI:SS')
This returns NULL instead of an error.
Hopefully, this is a lesson on why you should not store date/time values as strings. You can actually look for the bad values using:
select Request_Raised_Date, request_raised_time
from Xx_Lsp_Linestoppage_Entry
where to_date(Request_Raised_Date || ' ' || request_raised_time
default null on conversion error, 'DD-Mon-YYYY HH24:MI:SS') is null and
Request_Raised_Date is not null
This may give you some ideas on how to fix the data.

Oracle-Sqldeveloper function: compilation error in "END my_function;" statement

So i'm debugging a sql function with the compilation error:
Error(16,1): PLS-00103: Encountered the symbol "/"
..which is occurring at the very end of the function:
create or replace
function total_weekdays(fromdate in date, todate in date)
return number
as totaldays number := 0;
dates number := 0;
BEGIN
select to_number(count(dates)) into totaldays from
(select to_char(fromdate + level -1, 'dd/mm/YYYY DY') as dates
from dual connect by level <= todate - fromdate +1
minus
select to_char(ho_date, 'dd/mm/YYYY DY') as dates
from FS.fs_holiday
) where not regexp_like(dates,'SUN|SAT');
return totaldays;
END;
/
Prompt *** RPT_PACK_GEN_INV_MOVEMENT Package ***
CREATE OR REPLACE PACKAGE REPORTS_CLIENT."RPT_PACK_GEN_INV_MOVEMENT" AS
Procedure GEN_INV_MOVEMENT(pv_RunDate_i DATE default null);
Procedure RE_GEN_INV_MOVEMENT(pv_RunDate_i DATE default null);
Procedure GEN_INV_MOVEMENT_SUMMARY(pv_RunDate_i DATE default null);
Procedure GEN_Opening(pv_RunDate_i DATE);
end RPT_PACK_GEN_INV_MOVEMENT;
What you've shown compiles OK in a worksheet (without the FS. schema prefix for the demo):
create table fs_holiday(ho_date date);
create or replace
function total_weekdays(fromdate in date, todate in date)
return number
as totaldays number := 0;
dates number := 0;
BEGIN
select to_number(count(dates)) into totaldays from
(select to_char(fromdate + level -1, 'dd/mm/YYYY DY') as dates
from dual connect by level <= todate - fromdate +1
minus
select to_char(ho_date, 'dd/mm/YYYY DY') as dates
from fs_holiday
) where not regexp_like(dates,'SUN|SAT');
return totaldays;
END;
/
Function TOTAL_WEEKDAYS compiled
If you open the function in the object viewer and click on the SQL tab then it is shown without the trailing slash.
Adding the slash back in and then compiling does then give the error you're seeing,
Error(15,1): PLS-00103: Encountered the symbol "/" The symbol "/" was ignored.
In the object viewer context you should not have the slash. In the worksheet, as in SQL*Plus, SQL Developer:
... treats PL/SQL subprograms in the same manner as SQL commands, except that a semicolon (;) or a blank line does not terminate and execute a block. Terminate PL/SQL subprograms by entering a period (.) by itself on a new line. You can also terminate and execute a PL/SQL subprogram by entering a slash (/) by itself on a new line.
So in the worksheet the slash is necessary to delimit the end of the (named) block and identify the entirety of the create statement.
In the object viewer you are only seeing the code for that object, so there is no need to have that slash delimiter, and everything in the SQL window is treated as part of the object source code.
Similarly if you look in the user_source data dictionary view, there is no line stored for the slash.
select line, text from user_source where name = 'TOTAL_WEEKDAYS' order by line;
LINE TEXT
---------- --------------------------------------------------------------------------------
1 function total_weekdays(fromdate in date, todate in date)
2 return number
3 as totaldays number := 0;
4 dates number := 0;
5 BEGIN
6 select to_number(count(dates)) into totaldays from
7 (select to_char(fromdate + level -1, 'dd/mm/YYYY DY') as dates
8 from dual connect by level <= todate - fromdate +1
9 minus
10 select to_char(ho_date, 'dd/mm/YYYY DY') as dates
11 from fs_holiday
12 ) where not regexp_like(dates,'SUN|SAT');
13 return totaldays;
14 END;
14 rows selected.
It is part of the client's statement handling, not part of the function.
If you are in the object viewer then you can't create a second object in the same SQL window. That is the source code for the object you are viewing.
If you want to create multiple objects at once in a script then use a worksheet (right-click your connection and choose 'Open SQL Worksheet'), put all your code in, and then run as a script (F5). If you want to use the object view then expand your connection, right-click on the 'Packages' option, and choose 'New Package'.
Read more about managing objects and the SQL Worksheet.

All rows with date <= 90 days in oracle based on varchar2 date string [duplicate]

I have the following query that I am attempting to use as a COMMAND in a crystal report that I am working on.
SELECT * FROM myTable
WHERE to_date(myTable.sdate, 'MM/dd/yyyy') <= {?EndDate}
This works fine, however my only concern is that the date may not always be in the correct format (due to user error). I know that when the to_date function fails it throws an exception.. is it possible to handle this exception in such a way that it ignores the corresponding row in my SELECT statement? Because otherwise my report would break if only one date in the entire database is incorrectly formatted.
I looked to see if Oracle offers an isDate function, but it seems like you are supposed to just handle the exception. Any help would be greatly appreciated. Thanks!!
Echoing Tony's comment, you'd be far better off storing dates in DATE columns rather than forcing a front-end query tool to find and handle these exceptions.
If you're stuck with an incorrect data model, however, the simplest option in earlier versions is to create a function that does the conversion and handles the error,
CREATE OR REPLACE FUNCTION my_to_date( p_date_str IN VARCHAR2,
p_format_mask IN VARCHAR2 )
RETURN DATE
IS
l_date DATE;
BEGIN
l_date := to_date( p_date_str, p_format_mask );
RETURN l_date;
EXCEPTION
WHEN others THEN
RETURN null;
END my_to_date;
Your query would then become
SELECT *
FROM myTable
WHERE my_to_date(myTable.sdate, 'MM/dd/yyyy') <= {?EndDate}
Of course, you'd most likely want a function-based index on the MY_TO_DATE call in order to make this query reasonably efficient.
In 12.2, Oracle has added extensions to the to_date and cast functions to handle conversions that error
SELECT *
FROM myTable
WHERE to_date(myTable.sdate default null on conversion error, 'MM/dd/yyyy') <= {?EndDate}
You could also use the validate_conversion function if you're looking for all the rows that are (or are not) valid dates.
SELECT *
FROM myTable
WHERE validate_conversion( myTable.sdate as date, 'MM/DD/YYYY' ) = 1
If your data is not consistent and dates stored as strings may not be valid then you have 3 options.
Refactor your DB to make sure that the column stores a date datatype
Handle the exception of string to date in a stored procedure
Handle the exception of string to date in a (complex) record selection formula
I would suggest using the first option as your data should be consistent.
The second option will provide some flexibility and speed as the report will only fetch the rows that are needed.
The third option will force the report to fetch every record in the table and then have the report filter down the records.
I have the same problem... an old legacy database with varchar fields for dates and decades of bad data in the field. As much as I'd like to, I can't change the datatypes either. But I came up with this solution to find if a date is current, which seems to be what you're doing as well:
select * from MyTable
where regexp_like(sdate, '[0-1][0-9].[0-3][0-9].[0-9][0-9][0-9][0-9]')
-- make sure it's in the right format and ignore rows that are not
and substr(sdate,7,10) || substr(sdate,1,2) || substr(sdate,4,5) >= to_char({?EndDate}, 'YYYYMMDD')
-- put the date in ISO format and do a string compare
The benefit of this approach is it doesn't choke on dates like "February 30".
Starting from Oracle 12c there is no need to define a function to catch the conversion exception.
Oracle introduced an ON CONVERSION ERROR clause in the TO_DATE function.
Basically the clause suppress the error in converting of an invalid date string (typical errors are ORA-01843, ORA-01841, ORA-011861, ORA-01840) and returns a specified default value or null.
Example of usage
select to_date('2020-99-01','yyyy-mm-dd') from dual;
-- ORA-01843: not a valid month
select to_date('2020-99-01' default null on conversion error,'yyyy-mm-dd') from dual;
-- returns NULL
select to_date('2020-99-01' default '2020-01-01' on conversion error,'yyyy-mm-dd') from dual;
-- 01.01.2020 00:00:00
Solution for the Legacy Application
Let's assume there is a table with a date column stored as VARCHAR2(10)
select * from tab;
DATE_CHAR
----------
2021-01-01
2021-99-01
Using the above feature a VIRTUAL DATE column is defined, that either shows the DATE or NULL in case of the conversion error
alter table tab add (
date_d DATE as (to_date(date_char default null on conversion error,'yyyy-mm-dd')) VIRTUAL
);
select * from tab;
DATE_CHAR DATE_D
---------- -------------------
2021-01-01 01.01.2021 00:00:00
2021-99-01
The VIRTUAL column can be safely used because its format is DATE and if required an INDEX can be set up on it.
select * from tab where date_d = date'2021-01-01';
Since you say that you have "no access" to the database, I am assuming that you can not create any functions to help you with this and that you can only run queries?
If that is the case, then the following code should get you most of what you need with the following caveats:
1) The stored date format that you want to evaluate is 'mm/dd/yyyy'. If this is not the case, then you can alter the code to fit your format.
2) The database does not contain invalid dates such as Feb 30th.
First, I created my test table and test data:
create table test ( x number, sdate varchar2(20));
insert into test values (1, null);
insert into test values (2, '01/01/1999');
insert into test values (3, '1999/01/01');
insert into test values (4, '01-01-1999');
insert into test values (5, '01/01-1999');
insert into test values (6, '01-01/1999');
insert into test values (7, '12/31/1999');
insert into test values (8, '31/12/1999');
commit;
Now, the query:
WITH dates AS (
SELECT x
, sdate
, substr(sdate,1,2) as mm
, substr(sdate,4,2) as dd
, substr(sdate,7,4) as yyyy
FROM test
WHERE ( substr(sdate,1,2) IS NOT NAN -- make sure the first 2 characters are digits
AND to_number(substr(sdate,1,2)) between 1 and 12 -- and are between 0 and 12
AND substr(sdate,3,1) = '/' -- make sure the next character is a '/'
AND substr(sdate,4,2) IS NOT NAN -- make sure the next 2 are digits
AND to_number(substr(sdate,4,2)) between 1 and 31 -- and are between 0 and 31
AND substr(sdate,6,1) = '/' -- make sure the next character is a '/'
AND substr(sdate,7,4) IS NOT NAN -- make sure the next 4 are digits
AND to_number(substr(sdate,7,4)) between 1 and 9999 -- and are between 1 and 9999
)
)
SELECT x, sdate
FROM dates
WHERE to_date(mm||'/'||dd||'/'||yyyy,'mm/dd/yyyy') <= to_date('08/01/1999','mm/dd/yyyy');
And my results:
X SDATE
- ----------
2 01/01/1999
The WITH statement will do most of the validating to make sure that the sdate values are at least in the proper format. I had to break out each time unit month / day / year to do the to_date evaluation because I was still getting an invalid month error when I did a to_date on sdate.
I hope this helps.
Trust this reply clarifies...
there is no direct EXCEPTION HANDLER for invalid date.
One easy way is given below once you know the format like DD/MM/YYYY then below given REGEXP_LIKE function will work like a charm.
to_date() also will work, when invalid_date is found then cursor will goto OTHERS EXCEPTION. given below.
DECLARE
tmpnum NUMBER; -- (1=true; 0 = false)
ov_errmsg LONG;
tmpdate DATE;
lv_date VARCHAR2 (15);
BEGIN
lv_date := '6/2/2018'; -- this will fail in *regexp_like* itself
lv_date := '06/22/2018'; -- this will fail in *to_date* and will be caught in *exception WHEN OTHERS* block
lv_date := '07/03/2018'; -- this will succeed
BEGIN
tmpnum := REGEXP_LIKE (lv_date, '[0-9]{2}/[0-9]{2}/[0-9]{4}');
IF tmpnum = 0
THEN -- (1=true; 0 = false)
ov_errmsg := '1. INVALID DATE FORMAT ';
DBMS_OUTPUT.PUT_LINE (ov_errmsg);
RETURN;
END IF;
tmpdate := TO_DATE (lv_date, 'DD/MM/RRRR');
--tmpdate := TRUNC (NVL (to_date(lv_date,'DD/MM/RRRR'), SYSDATE));
tmpnum := 1;
EXCEPTION
WHEN OTHERS
THEN
BEGIN
tmpnum := 0;
ov_errmsg := '2. INVALID DATE FORMAT ';
DBMS_OUTPUT.PUT_LINE (ov_errmsg || SQLERRM);
RETURN;
END;
-- continue with your other query blocks
END;
-- continue with your other query blocks
DBMS_OUTPUT.PUT_LINE (tmpnum);
END;

Comparision of the timestamp in procedure not working

I have written a following query in my procedure which is not inserting the records in the TEST table. The KPI definition table has the following record:
KPI_DEF_ID KPI_FREQUENCY KPI_FREQ_TIME_UNIT EVENT_ID
1000136 30 MINUTE 10028
1000137 50 MINUTE 10028
I have a application in which user want to get the records depending on the timestamp. So user can enter in the application to get the records for example older than 30 min and newer than 24 hour. And the timestamp is changable. The older than timestamp comes from the KPI DEFINITION table and which is stored in the column KPI_FREQUENCY and KPI_FREQUENCY_UNIT and it can be changabler. And the newer than timestamp is fixed and i stored it in varaible LAST_OLDER_VAL and LAST_OLDER_VAL_UNIT. I used the insert using select query to store the records in table but its not working.
create or replace PROCEDURE "EXT_TEST" AS
LAST_WF_ID Number := 0;
--LAST_UNIT NUMBER:=10;
--LAST_UNIT_VAL VARCHAR2(20);
LAST_OLDER_VAL NUMBER := 24;
LAST_OLDER_VAL_UNIT VARCHAR2(10) := 'HOUR';
CURSOR WF_WORKFLOW_CUR IS
Select KPI_DEF_ID,KPI_FREQUENCY,KPI_FREQ_TIME_UNIT,EVENT_ID,BUSINESS_CHECK_PERIOD_ID FROM RATOR_MONITORING_CONFIGURATION.KPI_DEFINITION where EVENT_ID=10028;
BEGIN
--DBMS_OUTPUT.PUT_LINE('LAST_UNIT - ' || LAST_UNIT);
--DBMS_OUTPUT.PUT_LINE('LAST_UNIT_VAL - ' || LAST_UNIT_VAL);
-- removed, retrieve a new START_ID from source first, don't use the last id.
--SELECT LAST_TASK_ID INTO LAST_WF_ID FROM CAPTURING where DB_TABLE='TEMP_WF_WORKFLOW';
FOR WF_WORKFLOW_ROW IN WF_WORKFLOW_CUR
LOOP
--select MIN(ID) INTO LAST_WF_ID from WF_WORKFLOW#FONIC_RETAIL WF where WF.START_DATE > sysdate - numtodsinterval ( WF_WORKFLOW_ROW.KPI_FREQUENCY, WF_WORKFLOW_ROW.KPI_FREQ_TIME_UNIT );
Insert into TEST(ID,NAME,SUBSCRIPTION_ID,START_DATE,STATUS_ID,ACCOUNT_ID,END_DATE)
Select DISTINCT(WF.ID),WF.NAME,WF.SUBSCRIPTION_ID,WF.START_DATE,WF.STATUS_ID,WF.ACCOUNT_ID,WF.END_DATE
from WF_WORKFLOW#FONIC_RETAIL WF where WF.STATUS_ID = 0 and WF.NAME = 'SIGNUP_MOBILE_PRE_PAID'
and WF.START_DATE > SYSDATE - numtodsinterval ( LAST_OLDER_VAL, LAST_OLDER_VAL_UNIT
and WF.START_DATE < SYSDATE - numtodsinterval ( WF_WORKFLOW_ROW.KPI_FREQUENCY, WF_WORKFLOW_ROW.KPI_FREQ_TIME_UNIT ));
DBMS_OUTPUT.PUT_LINE('WF_WORKFLOW_ROW.KPI_FREQUENCY - ' || WF_WORKFLOW_ROW.KPI_FREQUENCY);
DBMS_OUTPUT.PUT_LINE('WF_WORKFLOW_ROW.KPI_FREQ_TIME_UNIT - ' || WF_WORKFLOW_ROW.KPI_FREQ_TIME_UNIT);
END LOOP;
END EXT_TEST;
You're currently looking for a start date that is older than 24 hours and newer than 30 minutes. Which is impossible, and not what you stated you needed, so that isn't what you mean really. Looks like you just have your < and > comparisons the wrong way around:
...
and WF.START_DATE > SYSDATE - numtodsinterval ( LAST_OLDER_VAL, LAST_OLDER_VAL_UNIT )
and WF.START_DATE < SYSDATE - numtodsinterval ( WF_WORKFLOW_ROW.KPI_FREQUENCY, WF_WORKFLOW_ROW.KPI_FREQ_TIME_UNIT );
Not directly relevant, but I'm not sure why you're using a loop for this, rather than a single insert ... select which joins WF_WORKFLOW_CUR and WF_WORKFLOW#FONIC_RETAIL. Or really why you'd use a stored procedure at all.