问题
The Paramterized Query with IN clause is not working; it not able to replace the value
PROCEDURE p_getdata(A IN LONG,B IN LONG,C IN LONG, cur OUT c_data)
AS
l_query LONG;
BEGIN
IF C IS NULL THEN
open cur for 'select firstname, lastname, streetname, city
from mytable
where zip IN(:A) AND streetnumber IN(:B) AND apt_num in(:C)' using A, B,C;
END IF;
END;
here
a ='202020';
b='12','13','10','92','02','02'
c='A','B'
In Db all datatype is varchar2. How to make it run and store the value is cursor?
回答1:
You may pass the comma separated list as a parameter (bind variable), but you are responsible for parsing it in a subquery. A solution based on this thread uses regexp_substr.
CREATE or REPLACE PROCEDURE p_getdata(A IN VARCHaR2, cur OUT sys_refcursor)
AS
BEGIN
open cur for 'with t1 as (select :A col from dual),
t2 as (select level lvl,to_number(regexp_substr(col,''[^,]+'', 1, level)) col
from t1 connect by regexp_substr(col, ''[^,]+'', 1, level) is not null)
select col as id from t2' using A;
END;
/
The procedure is simplified, but should provide a feeling how to use it.
The big advantage against the use of dynamic SQL (concatenation of strings) is that you need not parse the statement on each execution. Not to mention the security (scare of SQL injection).
Usage:
DECLARE
l_cur SYS_REFCURSOR;
l_id NUMBER;
BEGIN
p_getdata('1,1000,282828,4',l_cur);
LOOP
FETCH l_cur INTO l_id ;
EXIT WHEN l_cur%NOTFOUND;
dbms_output.put_line(l_id);
END LOOP;
END;
/
1
1000
282828
4
UPDATE
The above procedure is simplified, to get your functionality you should use a query like this in the CURSOR (i.e. first split all three parameters in separate subqueries using subquery factoring, than apply the results in your query)
CREATE or REPLACE PROCEDURE p_getdata(A IN VARCHAR2, B in VARCHAR2, c in VARCHAR2, cur OUT sys_refcursor)
AS
BEGIN
open cur for 'with ta1 as (select :A col from dual),
ta2 as (select level lvl,to_number(regexp_substr(col,''[^,]+'', 1, level)) col
from ta1 connect by regexp_substr(col, ''[^,]+'', 1, level) is not null),
tb1 as (select :B col from dual),
tb2 as (select level lvl,to_number(regexp_substr(col,''[^,]+'', 1, level)) col
from tb1 connect by regexp_substr(col, ''[^,]+'', 1, level) is not null),
tc1 as (select :C col from dual),
tc2 as (select level lvl,to_number(regexp_substr(col,''[^,]+'', 1, level)) col
from tc1 connect by regexp_substr(col, ''[^,]+'', 1, level) is not null)
select firstname, lastname, streetname, city
from mytable
where zip IN (select col from ta2) AND
streetnumber IN (select col from tb2) AND
apt_num in (select col from tc2)' using A, B, C;
END;
/
test passed
DECLARE
l_cur SYS_REFCURSOR;
l_firstname VARCHAR2(20);
l_lastname VARCHAR2(20);
l_streetname VARCHAR2(20);
l_city VARCHAR2(20);
BEGIN
p_getdata('1100,,1200','1,2','11,12' ,l_cur);
LOOP
FETCH l_cur INTO l_firstname, l_lastname, l_streetname, l_city;
EXIT WHEN l_cur%NOTFOUND;
dbms_output.put_line(l_firstname|| ' ' || l_lastname || ' ' || l_streetname || ' ' || l_city);
END LOOP;
END;
/
回答2:
The whole point of using parameters is to make the structure of the query separate from the data of the query. When you make a placeholder, you've essentially made a promise that it will only ever represent one value, not a list of values.
In your case, if you trust your data, you'll need to use string concatenation and omit the USING
:
OPEN cur FOR 'SELECT ... WHERE zip IN(' || A || ') AND ...';
回答3:
open cur for select firstname, lastname, streetname, city
from mytable
where zip (SELECT REGEXP_SUBSTR(A,'[^,]+', 1, LEVEL)
FROM DUAL
CONNECT BY REGEXP_SUBSTR(A, '[^,]+', 1, LEVEL) IS NOT NULL
AND streetnumber IN(SELECT REGEXP_SUBSTR(B,'[^,]+', 1, LEVEL)
FROM DUAL
CONNECT BY REGEXP_SUBSTR(B, '[^,]+', 1, LEVEL) IS NOT NULL
AND apt_num in(SELECT REGEXP_SUBSTR(C,'[^,]+', 1, LEVEL)
FROM DUAL
CONNECT BY REGEXP_SUBSTR(C, '[^,]+', 1, LEVEL) IS NOT NULL
It is working
来源:https://stackoverflow.com/questions/34497184/oracle-paramterized-query-with-in-clause-return-null-value