Oracle:带有 IN 子句 return 空值的参数化查询
Oracle: Paramterized Query with IN clause return null value
带有 IN 子句的参数化查询不起作用;它无法替换值
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;
这里
a ='202020';
b='12','13','10','92','02','02'
c='A','B'
在 Db 中,所有数据类型都是 varchar2。如何使其成为 运行 并将值存储为游标?
使用参数的全部意义在于使查询的结构与查询的数据分开。当您创建一个占位符时,您实际上已经承诺它只会代表 一个 值,而不是值列表。
在你的情况下,如果你信任你的数据,你将需要使用字符串连接并省略 USING
:
OPEN cur FOR 'SELECT ... WHERE zip IN(' || A || ') AND ...';
您可以将逗号分隔列表作为参数(绑定变量)传递,但您负责在子查询中对其进行解析。基于 this thread 的解决方案使用 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;
/
程序简化了,但应该给大家一个使用感受。
相对于使用动态 SQL(字符串连接)的最大优势是您无需在每次执行时都解析语句。更不用说安全性了(害怕 SQL 注入)。
用法:
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
更新
上述过程已简化,要获得您的功能,您应该在 CURSOR 中使用这样的查询(即首先使用子查询分解将所有三个参数拆分为单独的子查询,然后在查询中应用结果)
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;
/
测试通过
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;
/
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
带有 IN 子句的参数化查询不起作用;它无法替换值
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;
这里
a ='202020';
b='12','13','10','92','02','02'
c='A','B'
在 Db 中,所有数据类型都是 varchar2。如何使其成为 运行 并将值存储为游标?
使用参数的全部意义在于使查询的结构与查询的数据分开。当您创建一个占位符时,您实际上已经承诺它只会代表 一个 值,而不是值列表。
在你的情况下,如果你信任你的数据,你将需要使用字符串连接并省略 USING
:
OPEN cur FOR 'SELECT ... WHERE zip IN(' || A || ') AND ...';
您可以将逗号分隔列表作为参数(绑定变量)传递,但您负责在子查询中对其进行解析。基于 this thread 的解决方案使用 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;
/
程序简化了,但应该给大家一个使用感受。
相对于使用动态 SQL(字符串连接)的最大优势是您无需在每次执行时都解析语句。更不用说安全性了(害怕 SQL 注入)。
用法:
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
更新
上述过程已简化,要获得您的功能,您应该在 CURSOR 中使用这样的查询(即首先使用子查询分解将所有三个参数拆分为单独的子查询,然后在查询中应用结果)
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;
/
测试通过
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;
/
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