I have an Oracle (11g) SP which takes a comma separated string of inputs (eg 'Cats, Dogs, Monkeys'). The crux of the code is taken from Tony Andrews' blog and works as expected but it will not accept input strings greater than 4000 characters:
PROCEDURE delimstring_to_table ( p_delimstring IN VARCHAR2
, p_table OUT VARCHAR2_TABLE
, p_nfields OUT INTEGER
, p_delim IN VARCHAR2 DEFAULT ','
)
IS
v_string VARCHAR2(32767) := p_delimstring;
v_nfields PLS_INTEGER := 1;
v_table VARCHAR2_TABLE;
v_delimpos PLS_INTEGER := INSTR(p_delimstring, p_delim);
v_delimlen PLS_INTEGER := LENGTH(p_delim);
BEGIN
WHILE v_delimpos > 0
LOOP
v_table(v_nfields) := SUBSTR(v_string,1,v_delimpos-1);
v_string := SUBSTR(v_string,v_delimpos+v_delimlen);
v_nfields := v_nfields+1;
v_delimpos := INSTR(v_string, p_delim);
END LOOP;
v_table(v_nfields) := v_string;
p_table := v_table;
p_nfields := v_nfields;
END delimstring_to_table;
The functions above are then used inside any relevant SPs within the package:
PROCEDURE Get_Animals(
p_Animals IN VARCHAR2 := NULL
, resultset_out OUT resultset_typ
, error_out OUT VARCHAR2
)
IS
BEGIN
IF p_Animals IS NULL THEN
OPEN resultset_out FOR
SELECT /*+ ALL_ROWS */ * FROM ANIMALS ORDER BY NAME;
ELSE
OPEN resultset_out FOR
SELECT * FROM ANIMALS where NAME in (SELECT * FROM TABLE (Comma_To_Table(p_RICs)));
END IF;
error_out := NULL;
EXCEPTION
WHEN OTHERS THEN
error_out := 'Get_Animals() -> ' || SUBSTR(SQLERRM,1,200);
END Get_Animals;
If the input string is > 4000 characters, I get the following error from the SP:
ORA-00604: error occurred at recursive SQL level 1
ORA-01003: no statement parsed - GET_ANIMALS
I have two questions:
Any help or suggestions would be much appreciated.
Can I make the function work with input strings greater than 4000 characters? Yes, you can use for example CLOB
Is there a more effective way of achieving the same result? I saw in the comments of the blog a good answer, which is about a recursive solution.
just make some datatype changes for making it to work eg:
change the varchar2_table type to CLOB
TYPE varchar2_table IS TABLE OF CLOB INDEX BY BINARY_INTEGER;
change the VARCHAR2 datatype to CLOB in all p_delimstring occurences
change original SUBSTR functions to DBMS_LOB.SUBSTR (if you need more info about that: http://docs.oracle.com/cd/A91202_01/901_doc/appdev.901/a89852/dbms_23b.htm )
CREATE OR REPLACE PACKAGE parse AS /* || Package of utility procedures for parsing delimited or fixed position strings into tables || of individual values, and vice versa. */ TYPE varchar2_table IS TABLE OF CLOB INDEX BY BINARY_INTEGER; PROCEDURE delimstring_to_table ( p_delimstring IN CLOB , p_table OUT varchar2_table , p_nfields OUT INTEGER , p_delim IN VARCHAR2 DEFAULT ',' ); PROCEDURE table_to_delimstring ( p_table IN varchar2_table , p_delimstring OUT CLOB , p_delim IN VARCHAR2 DEFAULT ',' ); END parse; / CREATE OR REPLACE PACKAGE BODY parse AS PROCEDURE delimstring_to_table ( p_delimstring IN CLOB , p_table OUT varchar2_table , p_nfields OUT INTEGER , p_delim IN VARCHAR2 DEFAULT ',' ) IS v_string CLOB := p_delimstring; v_nfields PLS_INTEGER := 1; v_table varchar2_table; v_delimpos PLS_INTEGER := INSTR(p_delimstring, p_delim); v_delimlen PLS_INTEGER := LENGTH(p_delim); BEGIN WHILE v_delimpos > 0 LOOP v_table(v_nfields) := DBMS_LOB.SUBSTR(v_string,1,v_delimpos-1); v_string := DBMS_LOB.SUBSTR(v_string,v_delimpos+v_delimlen); v_nfields := v_nfields+1; v_delimpos := INSTR(v_string, p_delim); END LOOP; v_table(v_nfields) := v_string; p_table := v_table; p_nfields := v_nfields; END delimstring_to_table; PROCEDURE table_to_delimstring ( p_table IN varchar2_table , p_delimstring OUT CLOB , p_delim IN VARCHAR2 DEFAULT ',' ) IS v_nfields PLS_INTEGER := p_table.COUNT; v_string CLOB; BEGIN FOR i IN 1..v_nfields LOOP v_string := v_string || p_table(i); IF i != v_nfields THEN v_string := v_string || p_delim; END IF; END LOOP; p_delimstring := v_string; END table_to_delimstring; END parse; /
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.