Count of each characters in given string - oracle

I require the count of each character in a string.
Example:
SELECT ('aabcccdee') from dual;
Result:
a(1),b(2), c(3), d(1),e(2).
Thanks in advance.

You can use a hierarchical query to split your string into it individual characters; this is using a CTE just to supply your example value:
with t (value) as (
select 'aabcccdee' from dual
)
select substr(value, level, 1) as a_char
from t
connect by level <= length(value);
Then you can use aggregation to count how may times each appears:
with t (value) as (
select 'aabcccdee' from dual
)
select a_char, count(*) a_count
from (
select substr(value, level, 1) as a_char
from t
connect by level <= length(value)
)
group by a_char
order by a_char;
A_CH A_COUNT
---- ----------
a 2
b 1
c 3
d 1
e 2
And you can use listagg() (if you're on 11g or above) to aggregate those characters and counts into a single string if that's what you really want:
with t (value) as (
select 'aabcccdee' from dual
)
select listagg(a_char || '(' || count(*) || ')', ',') within group (order by a_char)
from (
select substr(value, level, 1) as a_char
from t
connect by level <= length(value)
)
group by a_char;
LISTAGG(A_CHAR||'('||COUNT(*)||')',',')WITHINGROUP(ORDERBYA_CHAR)
-----------------------------------------------------------------
a(2),b(1),c(3),d(1),e(2)
If you particularly want to do this in PL/SQL - because you value is already in a PL/SQL variable perhaps - you can do the same thing with a context switch:
set serveroutput on
declare
l_value varchar2(30) := 'aabcccdee';
l_result varchar2(100);
begin
select listagg(a_char || '(' || count(*) || ')', ',') within group (order by a_char)
into l_result
from (
select substr(l_value, level, 1) as a_char
from dual
connect by level <= length(l_value)
)
group by a_char;
dbms_output.put_line(l_result);
end;
/
a(2),b(1),c(3),d(1),e(2)
PL/SQL procedure successfully completed.

Related

How to check record exist before inserting in this query

I have following query which inserts (name & values) to the table and it works fine but I also need to check whether the data already exist or not in the table before inserting. If exist, no need of inserting again , just update or skip the loop but I am not able to make the logic in below query for this checking part. I appreciate your help on this. I am aware of Merge Into but I need to check multiple fields, in my case (name & values)
set serveroutput on
DECLARE
str VARCHAR2(100) := '1,2';
BEGIN
FOR i IN
(SELECT trim(regexp_substr(str, '[^,]+', 1, LEVEL)) l
FROM dual
CONNECT BY LEVEL <= regexp_count(str, ',')+1
)
LOOP
insert into TBL_TEST_CUSTOMER (NAME,VALUES)
SELECT
regexp_substr('Name:check values,Name:bv,Name:cv', '(Name:)?(.*?)(,Name:|$)', 1, level, NULL,
2) AS "CatName",i.l
FROM
dual
CONNECT BY
level <= regexp_count('Name:check values,Name:bv,Name:cv', 'Name:');
END LOOP;
END;
MERGE looks OK; another approach might be NOT EXISTS:
insert into TBL_TEST_CUSTOMER (NAME, VALUES)
select "CatName", l
from (SELECT regexp_substr('Name:check values,Name:bv,Name:cv', '(Name:)?(.*?)(,Name:|$)', 1, level, NULL,2) AS "CatName",
i.l
FROM dual
CONNECT BY level <= regexp_count('Name:check values,Name:bv,Name:cv', 'Name:')
) x
where not exists (select null
from tbl_test_cusomer
where name = x.name
and values = x.l
);
I think this solve my issues. please confirm my approach is correct. I appreciate any better way
set serveroutput on
DECLARE
str VARCHAR2(100) := '1,2';
BEGIN
FOR i IN
(SELECT trim(regexp_substr(str, '[^,]+', 1, LEVEL)) l
FROM dual
CONNECT BY LEVEL <= regexp_count(str, ',')+1
)
LOOP
MERGE INTO TBL_TEST_CUSTOMER TC USING
(SELECT TMP1.CatName
FROM
(SELECT
regexp_substr('Name:check values,Name:bv,Name:cv', '(Name:)?(.*?)(,Name:|$)', 1, level, NULL,
2) AS CatName
FROM
dual
CONNECT BY
level <= regexp_count('Name:check values,Name:bv,Name:cv', 'Name:')
) TMP1
) TMP ON (TC.NAME = TMP.CatName AND TC.VALUES= i.l )
WHEN NOT MATCHED THEN
INSERT
( NAME, VALUES
) VALUES
( TMP.CatName, i.l
);
END LOOP;
END;

How to retain the same case in the text in Oracle?

I have a table with columns word and sentence. The idea is to replace the words in the sentence with the link(includes the word itself) if the word is found in the word column. The query below replaces perfectly but since the link is constructed from the temp.word column, the case of the words in the sentence is changed to the case of the words in the word column. Is there a way to retain the same case in the sentence itself?
Create table temp(
id NUMBER,
word VARCHAR2(1000),
sentence VARCHAR2(2000)
);
insert into temp
SELECT 1,'automation testing', 'automtestingation Testing is popular kind of testing' FROM DUAL UNION ALL
SELECT 2,'testing','manual testing' FROM DUAL UNION ALL
SELECT 3,'manual testing','this is an old method of testing' FROM DUAL UNION ALL
SELECT 4,'punctuation','automation testing,manual testing,punctuation,automanual testing-testing' FROM DUAL UNION ALL
SELECT 5,'B-number analysis','B-number analysis table' FROM DUAL UNION ALL
SELECT 6,'B-number analysis table','testing B-number analysis' FROM DUAL UNION ALL
SELECT 7,'Not Matched','testing testing testing' FROM DUAL;
with words(id, word, word_length, search1, replace1, search2, replace2) as (
select id, word, length(word),
'(^|\W)' || REGEXP_REPLACE(word, '([][)(}{|^$\.*+?])', '\\\1') || '($|\W)',
'\1{'|| id ||'}\2',
'{'|| id ||'}',
'http://localhost/' || id || '/<u>' || word || '</u>'
FROM temp
)
, joined_data as (
select w.search1, w.replace1, w.search2, w.replace2,
s.rowid s_rid, s.sentence,
row_number() over(partition by s.rowid order by word_length desc) rn
from words w
join temp s
on instr(UPPER(s.sentence), UPPER(w.word)) > 0
and regexp_like(s.sentence, w.search1)
)
, unpivoted_data as (
select S_RID, SENTENCE, PHASE, SEARCH_STRING, REPLACE_STRING,
row_number() over(partition by s_rid order by phase, rn) rn,
case when row_number() over(partition by s_rid order by phase, rn)
= count(*) over(partition by s_rid)
then 1
else 0
end is_last
from joined_data
unpivot(
(search_string, replace_string)
for phase in ( (search1, replace1) as 1, (search2, replace2) as 2 ))
)
, replaced_data(S_RID, RN, is_last, SENTENCE) as (
select S_RID, RN, is_last,
regexp_replace(SENTENCE, search_string, replace_string,1,0,'i')
from unpivoted_data
where rn = 1
union all
select n.S_RID, n.RN, n.is_last,
case when n.phase = 1
then regexp_replace(o.SENTENCE, n.search_string, n.replace_string,1,0,'i')
else replace(o.SENTENCE, n.search_string, n.replace_string)
end
from unpivoted_data n
join replaced_data o
on o.s_rid = n.s_rid and n.rn = o.rn + 1
)
select s_rid, sentence from replaced_data
where is_last = 1
order by s_rid;
For example, for id = 1, the sentence is automtestingation Testing is popular kind of testing
After replacement it will be automtestingation http://localhost/2/<u>testing</u> is popular kind of http://localhost/2/<u>testing</u>.
The word Testing is replaced with testing(from the temp.word column).
The expected outcome is
automtestingation http://localhost/2/<u>Testing</u> is popular kind of http://localhost/2/<u>testing</u>
Oracle Setup:
Create table temp(
id NUMBER,
word VARCHAR2(1000),
Sentence VARCHAR2(2000)
);
insert into temp
SELECT 1,'automation testing', 'automtestingation TeStInG TEST is popular kind of testing' FROM DUAL UNION ALL
SELECT 2,'testing','manual testing' FROM DUAL UNION ALL
select 2,'test', 'test' FROM DUAL UNION ALL
SELECT 3,'manual testing','this is an old method of testing' FROM DUAL UNION ALL
SELECT 4,'punctuation','automation testing,manual testing,punctuation,automanual testing-testing' FROM DUAL UNION ALL
SELECT 5,'B-number analysis','B-number analysis table' FROM DUAL UNION ALL
SELECT 6,'B-number analysis table','testing B-number analysis' FROM DUAL UNION ALL
SELECT 7,'Not Matched','testing testing testing' FROM DUAL UNION ALL
SELECT 8,'^[($','testing characters ^[($ that need escaping in a regular expression' FROM DUAL;
SQL Types:
CREATE TYPE stringlist IS TABLE OF VARCHAR2(4000);
/
CREATE TYPE intlist IS TABLE OF NUMBER(20,0);
/
PL/SQL Function:
CREATE FUNCTION replace_words(
word_list IN stringlist,
id_list IN intlist,
sentence IN temp.sentence%TYPE
) RETURN temp.sentence%TYPE
IS
p_sentence temp.sentence%TYPE := UPPER( sentence );
p_pos PLS_INTEGER := 1;
p_min_word_index PLS_INTEGER;
p_word_index PLS_INTEGER;
p_start PLS_INTEGER;
p_index PLS_INTEGER;
o_sentence temp.sentence%TYPE;
BEGIN
LOOP
p_min_word_index := NULL;
p_index := NULL;
FOR i IN 1 .. word_list.COUNT LOOP
p_word_index := p_pos;
LOOP
p_word_index := INSTR( p_sentence, word_list(i), p_word_index );
EXIT WHEN p_word_index = 0;
IF ( p_word_index > 1
AND REGEXP_LIKE( SUBSTR( p_sentence, p_word_index - 1, 1 ), '\w' )
)
OR REGEXP_LIKE( SUBSTR( p_sentence, p_word_index + LENGTH( word_list(i) ), 1 ), '\w' )
THEN
p_word_index := p_word_index + 1;
CONTINUE;
END IF;
IF p_min_word_index IS NULL OR p_word_index < p_min_word_index THEN
p_min_word_index := p_word_index;
p_index := i;
END IF;
EXIT;
END LOOP;
END LOOP;
IF p_index IS NULL THEN
o_sentence := o_sentence || SUBSTR( sentence, p_pos );
EXIT;
ELSE
o_sentence := o_sentence
|| SUBSTR( sentence, p_pos, p_min_word_index - p_pos )
|| 'http://localhost/'
|| id_list(p_index)
|| '/<u>'
|| SUBSTR( sentence, p_min_word_index, LENGTH( word_list( p_index ) ) )
|| '</u>';
p_pos := p_min_word_index + LENGTH( word_list( p_index ) );
END IF;
END LOOP;
RETURN o_sentence;
END;
/
Merge:
MERGE INTO temp dst
USING (
WITH lists ( word_list, id_list ) AS (
SELECT CAST(
COLLECT(
UPPER( word )
ORDER BY LENGTH( word ) DESC, UPPER( word ) ASC, ROWNUM
)
AS stringlist
),
CAST(
COLLECT(
id
ORDER BY LENGTH( word ) DESC, UPPER( word ) ASC, ROWNUM
)
AS intlist
)
FROM temp
)
SELECT t.ROWID rid,
replace_words(
word_list,
id_list,
sentence
) AS replaced_sentence
FROM temp t
CROSS JOIN lists
) src
ON ( dst.ROWID = src.RID )
WHEN MATCHED THEN
UPDATE SET sentence = src.replaced_sentence;
Output:
SELECT * FROM temp;
ID | WORD | SENTENCE
-: | :---------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1 | automation testing | automtestingation http://localhost/2/<u>TeStInG</u> http://localhost/2/<u>TEST</u> is popular kind of http://localhost/2/<u>testing</u>
2 | testing | http://localhost/3/<u>manual testing</u>
2 | test | http://localhost/2/<u>test</u>
3 | manual testing | this is an old method of http://localhost/2/<u>testing</u>
4 | punctuation | http://localhost/1/<u>automation testing</u>,http://localhost/3/<u>manual testing</u>,http://localhost/4/<u>punctuation</u>,automanual http://localhost/2/<u>testing</u>-http://localhost/2/<u>testing</u>
5 | B-number analysis | http://localhost/6/<u>B-number analysis table</u>
6 | B-number analysis table | http://localhost/2/<u>testing</u> http://localhost/5/<u>B-number analysis</u>
7 | Not Matched | http://localhost/2/<u>testing</u> http://localhost/2/<u>testing</u> http://localhost/2/<u>testing</u>
8 | ^[($ | http://localhost/2/<u>testing</u> characters http://localhost/8/<u>^[($</u> that need escaping in a regular expression
db<>fiddle here
While there's certainly a way to do this in a single SQL statement, I think this problem is better solved with a separate function:
create or replace function replace_words(p_word varchar2, p_sentence varchar2) return varchar2 is
v_match_position number;
v_match_count number := 0;
v_new_sentence varchar2(4000) := p_sentence;
begin
--Find all matches.
loop
--Find Nth case-insensitive match
v_match_count := v_match_count + 1;
v_match_position := regexp_instr(
srcstr => v_new_sentence,
pattern => p_word,
occurrence => v_match_count,
modifier => 'i');
exit when v_match_position = 0;
--Insert text, instead of replacing, to keep the original case.
v_new_sentence :=
substr(v_new_sentence, 1, v_match_position - 1) || 'http://localhost/2/<u>'||
substr(v_new_sentence, v_match_position, length(p_word)) || '</u>'||
substr(v_new_sentence, v_match_position + length(p_word));
end loop;
return v_new_sentence;
end;
/
Then the SQL query looks like this:
select id, word, sentence, replace_words(word, sentence) from temp;

TRUNC(date) with subquery in oracle

I have a IF condition which checks the dates in the subquery as shown below
IF (TRUNC(lv_d_itr) IN
(SELECT next_day(TRUNC(to_date('01-01-17','dd-mm-yy'),'YYYY') + 14*(level-1), 'WED' )+7
FROM dual
CONNECT BY level <= 26)) THEN
Why am i getting the below error? usage is wrong?
PLS-00405: subquery not allowed in this context
What could be the alternate solution?
You cannot use a sub-query in a pl/sql IF statement:
BEGIN
IF 'X' IN ( SELECT DUMMY FROM DUAL ) THEN
DBMS_OUTPUT.PUT_LINE( 'X' );
END IF;
END;
/
Will error with PLS-00405: subquery not allowed in this context
You can refactor it to get the same effect:
DECLARE
p_exists NUMBER;
BEGIN
SELECT CASE WHEN 'X' IN ( SELECT DUMMY FROM DUAL )
THEN 1
ELSE 0
END
INTO p_exists
FROM DUAL;
IF p_exists = 1 THEN
DBMS_OUTPUT.PUT_LINE( 'X' );
END IF;
END;
/
You can edit this in different ways, a simple one could be something like:
declare
n number;
begin
select count(1)
into n
from
(
SELECT next_day(TRUNC(to_date('01-01-17','dd-mm-yy'),'YYYY') + 14*(level-1), 'MER' )+7 as x
FROM dual
CONNECT BY level <= 26
)
where x = TRUNC(lv_d_itr);
if n > 0
then ...
end if;
...
end;

Output parameter value is shown as 'invalid identifier'

I am trying to retrieve values from temporarily created tables. But the return value throws the error 'Invalid Identifier'
create or replace procedure edu_stream (input in varchar2,vals out varchar2)
as
inp varchar2(30);
valu varchar2(30);
begin
inp:=input;
if inp='secondary education' then
Execute immediate'WITH secedu as (
(SELECT "ICSE" as name FROM dual ) UNION
(SELECT "CBSE" as name FROM dual ) UNION
(SELECT "STATE BOARD" as name FROM dual)
)
SELECT name into valu from(SELECT name
FROM secedu ORDER BY DBMS_RANDOM.RANDOM)where rownum<2';
vals:=valu;
else
if inp='intermediate education' then
Execute immediate'WITH intedu as (
(SELECT "MPC" as name FROM dual ) UNION
(SELECT "BIPC" as name FROM dual ) UNION
(SELECT "MBIPC" as name FROM dual) UNION
(SELECT "CEC" as name FROM dual)
)
SELECT name into valu from(SELECT name
FROM intedu ORDER BY DBMS_RANDOM.RANDOM)where rownum<2';
vals:=valu;
else
if inp='Graduation' then
Execute immediate'WITH gedu as (
(SELECT "ECE" as name FROM dual ) UNION
(SELECT "CSE" as name FROM dual ) UNION
(SELECT "CE" as name FROM dual) UNION
(SELECT "EEE" as name FROM dual)UNION
(SELECT "ME" as name FROM dual)UNION
(SELECT "AE" as name FROM dual)UNION
(SELECT "BIOTECH" as name FROM dual)UNION
(SELECT "EIE" as name FROM dual)
)
SELECT name into valu from(SELECT name
FROM gedu ORDER BY DBMS_RANDOM.RANDOM)where rownum<2';
vals:=valu;
else
if inp='post-graduation' then
Execute immediate'WITH pgedu as (
(SELECT "MCA" as name FROM dual ) UNION
(SELECT "MTECH" as name FROM dual ) UNION
(SELECT "MSC" as name FROM dual) UNION
(SELECT "MBA" as name FROM dual)
)
SELECT name into valu from(SELECT name
FROM pgedu ORDER BY DBMS_RANDOM.RANDOM)where rownum<2';
vals:=valu;
else
if inp='phd'then
Execute immediate' WITH phdedu as (
(SELECT "Doctorate of philosophy" as name FROM dual ) UNION
(SELECT "doctorate of medicine" as name FROM dual ) UNION
(SELECT "doctorate of science" as name FROM dual) UNION
(SELECT "Doctorate of computer sciences" as name FROM dual)
)
SELECT name into valu from(SELECT name
FROM phdgedu ORDER BY DBMS_RANDOM.RANDOM)where rownum<2';
vals:=valu;
end if;
end if;
end if;
end if;
end if;
end;
Execution:
declare
value1 varchar2(30);
cv varchar2(30);
begin
cv:='secondary education';
edu_stream(cv,value1);
dbms_output.put_line('val is'||value1);
end;
Error report:
Error starting at line 2 in command: declare value1 varchar2(30); cv
varchar2(30); begin cv:='secondary education'; edu_stream(cv,value1);
dbms_output.put_line('val is'||value1); end; Error report: ORA-00904:
"ICSE": invalid identifier ORA-06512: at "DATAFOCUS_GROUP.EDU_STREAM",
line 9 ORA-06512: at line 6
00904. 00000 - "%s: invalid identifier"
*Cause:
*Action:
if I use 'ICSE'instead of "ICSE"
ERROR SHOWS-
PLS-00103: Encountered the symbol "ICSE" when expecting one of the
following:
ERROR 103 * & = - + ; < / > at in is mod remainder not rem
return
returning <> or != or ~= >= <= <> and or
like like2 like4 likec between into using || multiset bulk
member submultiset
You can avoid dynamic SQL; also, probably due to confusion created by dynamic sql, you are using " instead of '.
You can re-write your code as:
CREATE OR REPLACE PROCEDURE edu_stream(input IN VARCHAR2, vals OUT VARCHAR2) AS
inp VARCHAR2(30);
valu VARCHAR2(30);
BEGIN
inp := input;
IF inp = 'secondary education'
THEN
WITH secedu AS
((SELECT 'ICSE' AS name FROM DUAL)
UNION
(SELECT 'CBSE' AS name FROM DUAL)
UNION
(SELECT 'STATE BOARD' AS name FROM DUAL))
SELECT name
INTO valu
FROM ( SELECT name
FROM secedu
ORDER BY DBMS_RANDOM.RANDOM)
WHERE ROWNUM < 2;
vals := valu;
ELSE
IF inp = 'intermediate education'
THEN
WITH intedu AS
((SELECT 'MPC' AS name FROM DUAL)
UNION
(SELECT 'BIPC' AS name FROM DUAL)
UNION
(SELECT 'MBIPC' AS name FROM DUAL)
UNION
(SELECT 'CEC' AS name FROM DUAL))
SELECT name
INTO valu
FROM ( SELECT name
FROM intedu
ORDER BY DBMS_RANDOM.RANDOM)
WHERE ROWNUM < 2;
vals := valu;
ELSE
IF inp = 'Graduation'
THEN
WITH gedu AS
((SELECT 'ECE' AS name FROM DUAL)
UNION
(SELECT 'CSE' AS name FROM DUAL)
UNION
(SELECT 'CE' AS name FROM DUAL)
UNION
(SELECT 'EEE' AS name FROM DUAL)
UNION
(SELECT 'ME' AS name FROM DUAL)
UNION
(SELECT 'AE' AS name FROM DUAL)
UNION
(SELECT 'BIOTECH' AS name FROM DUAL)
UNION
(SELECT 'EIE' AS name FROM DUAL))
SELECT name
INTO valu
FROM ( SELECT name
FROM gedu
ORDER BY DBMS_RANDOM.RANDOM)
WHERE ROWNUM < 2;
vals := valu;
ELSE
IF inp = 'post-graduation'
THEN
WITH pgedu AS
((SELECT 'MCA' AS name FROM DUAL)
UNION
(SELECT 'MTECH' AS name FROM DUAL)
UNION
(SELECT 'MSC' AS name FROM DUAL)
UNION
(SELECT 'MBA' AS name FROM DUAL))
SELECT name
INTO valu
FROM ( SELECT name
FROM pgedu
ORDER BY DBMS_RANDOM.RANDOM)
WHERE ROWNUM < 2;
vals := valu;
ELSE
IF inp = 'phd'
THEN
WITH phdedu AS
((SELECT 'Doctorate of philosophy' AS name FROM DUAL)
UNION
(SELECT 'doctorate of medicine' AS name FROM DUAL)
UNION
(SELECT 'doctorate of science' AS name FROM DUAL)
UNION
(SELECT 'Doctorate of computer sciences' AS name FROM DUAL))
SELECT name
INTO valu
FROM ( SELECT name
FROM phdgedu
ORDER BY DBMS_RANDOM.RANDOM)
WHERE ROWNUM < 2;
vals := valu;
END IF;
END IF;
END IF;
END IF;
END IF;
END;
Also, please notice that the variables inp and valu are not strictly necessary: you can simply use the parameters to check the input value and build the output parameter.
In case you need do use dynamic SQL (not here, but maybe in the future) the right way is something like:
declare
a number;
begin
execute immediate 'select 1 from dual' into a;
end;
As an alternative answer sticking with your dynamic SQL.
personal preference: i´d allways end a line with ' ||, to make it clear you are not missing a whitespace (even though it should just execute fine).
remove the into valu from the dynamic sql and make it a execute immediate 'query' into vals clause.
As an example i´m just using your first query:
Execute immediate 'WITH secedu as ( ' ||
'(SELECT ''ICSE'' as name FROM dual ) UNION ' ||
'(SELECT ''CBSE'' as name FROM dual ) UNION ' ||
'(SELECT ''STATE'' BOARD" as name FROM dual) ' ||
') ' ||
'SELECT name from(SELECT name ' ||
'FROM secedu ORDER BY DBMS_RANDOM.RANDOM)where rownum<2'
into vals;
You might have your own learning objectives but when those put aside the code is simply awful and unnecessary complex PL/SQL. Here is a partial but completely functional rewrite with references to relevant Oracle PL/SQL documentation. Hope you'll find the presented ideas useful !
-- blocks: http://docs.oracle.com/database/121/LNPLS/overview.htm#LNPLS141
declare
-- nested tables: http://docs.oracle.com/database/121/LNPLS/composites.htm#LNPLS99981
type str_list_t is table of varchar2(32767);
-- subprograms: http://docs.oracle.com/database/121/LNPLS/subprograms.htm#LNPLS008
-- common parts of f() refactored to r()
function r(p_list in str_list_t) return varchar2 is
begin
return p_list(floor(dbms_random.value(1, p_list.count + 1)));
end;
function f(p_edu_level in varchar2) return varchar2 is
begin
return
-- simple case: http://docs.oracle.com/database/121/LNPLS/controlstatements.htm#LNPLS394
case p_edu_level
when 'secondary' then r(str_list_t('ICSE', 'CBSE', 'STATE BOARD'))
when 'intermediate' then r(str_list_t('MPC', 'BIPC', 'MIPC', 'CEC'))
-- add here your other education levels, you should see the pattern ...
else null
end;
end;
begin
-- for loop: http://docs.oracle.com/database/121/LNPLS/controlstatements.htm#LNPLS411
for i in 1 .. 10
loop
dbms_output.put_line('secondary: ' || f('secondary'));
dbms_output.put_line('intermediate: ' || f('intermediate'));
end loop;
dbms_output.put_line('batman: ' || f('batman'));
end;
/

ORA-01861: literal does not match format string.while executing procedure

I have written procedure which have date paramters defined as below:
in_Spendpaidstartdt IN DATE,
in_Spendpaidenddt IN DATE,
while with in procedure i am calling these paramters as:
AND ( in_Spendpaidstartdt IS NULL
OR err.Spendpaiddt >= in_Spendpaidstartdt)
AND ( in_Spendpaidenddt IS NULL
OR err.Spendpaiddt <= in_Spendpaidenddt));
however oracle is giving following error:
"ORA-01861: literal does not match format string"
Some one please suggest the work around.
Here is dummy:
CREATE OR REPLACE PROCEDURE XYZ (
in_startdt IN DATE,
in_enddt IN DATE,
output OUT SYS_REFCURSOR)
IS
rcrdnums VARCHAR2 (32767);
rcrd_cnt INT;
BEGIN
rcrd_cnt := 500;
SELECT RTRIM (
XMLCAST (
XMLAGG (XMLELEMENT (e, RCRDNUM) ORDER BY RCRDNUM) AS CLOB),
',')
INTO rcrdnums
FROM (SELECT (ERR.RCRDNUM || ',') AS RCRDNUM
FROM Table_NAME ERR
WHERE ROWNUM <= rcrd_cnt
and ( in_startdt IS NULL
OR to_date(err.paiddt, 'dd/mm/yyyy') >= to_date(in_startdt, 'dd/mm/yyyy'))
AND ( in_enddt IS NULL
OR to_date(err.paiddt, 'dd/mm/yyyy') <= to_date(in_enddt, 'dd/mm/yyyy')));
IF LENGTH (rcrdnums) = 1
THEN
rcrdnums := NULL;
ELSE
rcrdnums := rcrdnums;
--SUBSTR (rcrdnums, 1, LENGTH (rcrdnums) - 1);
END IF;
DBMS_OUTPUT.PUT_LINE (rcrdnums);
OPEN outputFOR
SELECT *
FROM Table_NAME ERR
INNER JOIN ( SELECT REGEXP_SUBSTR (rcrdnums,
'[^,]+',
1,
LEVEL)
AS EVENT
FROM DUAL
CONNECT BY REGEXP_SUBSTR (rcrdnums,
'[^,]+',
1,
LEVEL)
IS NOT NULL) EVENT_P
ON EVENT_P.EVENT = ERR.RCRDNUM;
END;
/
As already mentioned to #XING, your issues are two-fold.
You are forcing Oracle to do an implicit conversion of a DATE back to a string, when you used to_date on something that's already a DATE - something I've already mentioned elsewhere on stackoverflow!
You are (probably) not passing in the parameters correctly when calling your procedure.
Here is how I'd amend your procedure:
CREATE OR REPLACE PROCEDURE XYZ (
in_startdt IN DATE,
in_enddt IN DATE,
output OUT SYS_REFCURSOR)
IS
rcrdnums VARCHAR2 (32767);
rcrd_cnt INT;
BEGIN
rcrd_cnt := 500;
SELECT RTRIM (
XMLCAST (
XMLAGG (XMLELEMENT (e, RCRDNUM) ORDER BY RCRDNUM) AS CLOB),
',')
INTO rcrdnums
FROM (SELECT (ERR.RCRDNUM || ',') AS RCRDNUM
FROM Table_NAME ERR
WHERE ROWNUM <= rcrd_cnt
and ( in_startdt IS NULL
OR to_date(err.paiddt, 'dd/mm/yyyy') >= in_startdt) -- in_startdt is already a DATE, so no need to convert it
AND ( in_enddt IS NULL
OR to_date(err.paiddt, 'dd/mm/yyyy') <= in_enddt)); -- in_enddt is already a DATE, so no need to convert it
IF LENGTH (rcrdnums) = 1
THEN
rcrdnums := NULL;
ELSE
rcrdnums := rcrdnums;
--SUBSTR (rcrdnums, 1, LENGTH (rcrdnums) - 1);
END IF;
DBMS_OUTPUT.PUT_LINE (rcrdnums);
OPEN output FOR
SELECT *
FROM Table_NAME ERR
INNER JOIN ( SELECT REGEXP_SUBSTR (rcrdnums,
'[^,]+',
1,
LEVEL)
AS EVENT
FROM DUAL
CONNECT BY REGEXP_SUBSTR (rcrdnums,
'[^,]+',
1,
LEVEL)
IS NOT NULL) EVENT_P
ON EVENT_P.EVENT = ERR.RCRDNUM;
END;
/
And to test, I'd call your procedure like so:
declare
v_refcur sys_refcursor;
begin
xyz(in_startdt => to_date('01/10/2016', 'dd/mm/yyyy'),
in_enddt => to_date('05/10/2016', 'dd/mm/yyyy'),
output => v_refcur);
end;
/
N.B. it's bad practice to use "select *" in production code - you should explicitly specify the columns you're wanting to get back; that way, if someone adds a column, your code won't cause something to break because it won't pass that extra column along.

Resources