当我只有一个状态代码作为参数时,这是有效的。
当我在parm_list中有多个state_code时,如何让代码生效?
要求:
(1)我不想在光标定义中硬编码状态代码
(2)我确实想在where子句中允许多个州代码
例如:我想为 parm_list =('NY','NJ','NC')运行此代码。 我在将parm_list中的单引号与'where state_code in'查询中的单引号进行协调时遇到了困难。
set serveroutput on;
DECLARE
parm_list varchar2(40);
cursor get_state_codes(in_state_codes varchar2)
is
select state_name, state_code from states
where state_code in (in_state_codes);
BEGIN
parm_list := 'NY';
for get_record in get_state_codes(parm_list) loop
dbms_output.put_line(get_record.state_name || get_record.state_code);
end loop;
END;
答案 0 :(得分:11)
从编码的角度来看,使用动态SQL是最简单的方法。但是,动态SQL的问题在于,您必须对查询的每个不同版本进行硬解析,这不仅可能会对CPU造成负担,而且可能会使用大量不可共享的SQL语句来泛滥共享池。你想要缓存的语句,导致更多的硬解析和共享池碎片错误。如果你每天运行一次,那可能不是一个主要问题。如果数百人每天执行数千次,那可能是一个主要问题。
动态SQL方法的一个示例
SQL> ed
Wrote file afiedt.buf
1 declare
2 l_deptnos varchar2(100) := '10,20';
3 l_rc sys_refcursor;
4 l_dept_rec dept%rowtype;
5 begin
6 open l_rc for 'select * from dept where deptno in (' || l_deptnos || ')';
7 loop
8 fetch l_rc into l_dept_rec;
9 exit when l_rc%notfound;
10 dbms_output.put_line( l_dept_rec.dname );
11 end loop;
12 close l_rc;
13* end;
SQL> /
ACCOUNTING
RESEARCH
PL/SQL procedure successfully completed.
或者,您可以使用集合。这样做的好处是可以生成单个可共享游标,因此您不必担心硬解析或泛滥共享池。但它可能需要更多的代码。处理集合的最简单方法
SQL> ed
Wrote file afiedt.buf
1 declare
2 l_deptnos tbl_deptnos := tbl_deptnos(10,20);
3 begin
4 for i in (select *
5 from dept
6 where deptno in (select column_value
7 from table(l_deptnos)))
8 loop
9 dbms_output.put_line( i.dname );
10 end loop;
11* end;
SQL> /
ACCOUNTING
RESEARCH
PL/SQL procedure successfully completed.
另一方面,如果您真的必须以逗号分隔的值列表开头,那么您必须先将该字符串解析为集合,然后才能使用它。有多种方法可以解析分隔的字符串 - 我个人最喜欢的是在分层查询中使用正则表达式,但你当然可以编写一个程序方法
SQL> ed
Wrote file afiedt.buf
1 declare
2 l_deptnos tbl_deptnos;
3 l_deptno_str varchar2(100) := '10,20';
4 begin
5 select regexp_substr(l_deptno_str, '[^,]+', 1, LEVEL)
6 bulk collect into l_deptnos
7 from dual
8 connect by level <= length(replace (l_deptno_str, ',', NULL));
9 for i in (select *
10 from dept
11 where deptno in (select column_value
12 from table(l_deptnos)))
13 loop
14 dbms_output.put_line( i.dname );
15 end loop;
16* end;
17 /
ACCOUNTING
RESEARCH
PL/SQL procedure successfully completed.
答案 1 :(得分:7)
一种选择是使用INSTR而不是IN:
SELECT uo.object_name
,uo.object_type
FROM user_objects uo
WHERE instr(',TABLE,VIEW,', ',' || uo.object_type || ',') > 0;
虽然这看起来很难看,但它运行良好,只要没有使用正在测试的列的索引(因为这可以防止使用任何索引),性能不会受到太大影响。例如,如果被测试的列是主键,那么不应该使用它。
另一种选择是:
SELECT uo.object_name
,uo.object_type
FROM user_objects uo
WHERE uo.object_type IN
(SELECT regexp_substr('TABLE,VIEW', '[^,]+', 1, LEVEL)
FROM dual
CONNECT BY regexp_substr('TABLE,VIEW', '[^,]+', 1, LEVEL) IS NOT NULL);
在这种情况下,值列表应该连接成一个varchar变量,用逗号(或任何你喜欢的东西)分隔。