在oracle中将where子句动态添加到游标
我有一个plsql程序,它接受某些参数,例如v_名称、v_国家、v_类型 我希望有一个带有select语句的游标,如下所示:在oracle中将where子句动态添加到游标,oracle,plsql,database-cursor,Oracle,Plsql,Database Cursor,我有一个plsql程序,它接受某些参数,例如v_名称、v_国家、v_类型 我希望有一个带有select语句的游标,如下所示: select column from table1 t1, table2 t2 where t1.name = v_name and t1.country = v_country and t1.id = t2.id and t2.type = v_type select column from table1 t1, table2 t2 where t1.name = n
select column from table1 t1, table2 t2
where t1.name = v_name
and t1.country = v_country
and t1.id = t2.id
and t2.type = v_type
select column from table1 t1, table2 t2
where t1.name = nvl(v_name, t1.name)
and t1.country = nvl(v_country, t1.country)
and t1.id = t2.id
and t2.type = nvl(v_type, t2.type)
open c1 for l_sql using v_name, v_country;
如果某些参数为空,我只能将相关where子句添加到游标中吗?或者有更好的方法来实现这一点吗?一种方法是将查询建立为字符串,然后使用最好的方法是使用DBMS\u SQL 创建一个表示SQL语句的字符串。您仍然使用绑定变量。很痛 它是这样的(我还没有编译这个,但应该很接近):- 与仅内联编写SQL相比,这种方法非常痛苦,除非您有大量的列,否则有时使用以下语法编写两个不同的版本会更容易:
FOR r IN (SELECT blah FROM blah WHERE t1 = v_t1) LOOP
func( r.blah );
END LOOP;
这不是你要问的直接问题,但它可能是一个可接受的解决方案:
select column from table1 t1, table2 t2
where
(v_name is null or t1.name = v_name)
and (v_country is null or t1.country = v_country)
and t1.id = t2.id
and (v_type is null or t2.type = v_type)
要做到这一点,最好的方法是使用Oracle的应用程序上下文功能,最好将其定义为最佳性能和安全性 更快的方法是hamishmcn建议的,使用executeimmediate。我会选择它,而不是WW每次建议的DBMS_SQL 另一种写得最快但性能不好的方法是:
select column from table1 t1, table2 t2
where t1.name = v_name
and t1.country = v_country
and t1.id = t2.id
and t2.type = v_type
select column from table1 t1, table2 t2
where t1.name = nvl(v_name, t1.name)
and t1.country = nvl(v_country, t1.country)
and t1.id = t2.id
and t2.type = nvl(v_type, t2.type)
open c1 for l_sql using v_name, v_country;
您不必使用dbms_sql来解决此问题 您仍然可以通过使用ref游标来使用普通游标 样本:
DECLARE
TYPE cursor_ref IS REF CURSOR;
c1 cursor_ref;
r1 table1.column%type;
BEGIN
l_sql := 'select t1.column from table1 t1, table2 t2 where t1.id = t2.id ';
if v_name is not null then
l_sql := l_sql||' and t1.name = '||v_name ;
end if;
if v_country is not null then
l_sql := l_sql||' and t1.country = '||v_country';
end if;
if v_type is not null then
l_sql := l_sql||' and t2.type = '||v_type';
end if;
open c1 for l_sql;
loop
fetch c1 into r1;
exit when c1%notfound;
-- do something
end loop;
close c1;
end;
/
您可以通过如下方式使用命令“using”绑定变量,从而更好地实现这一点:
select column from table1 t1, table2 t2
where t1.name = v_name
and t1.country = v_country
and t1.id = t2.id
and t2.type = v_type
select column from table1 t1, table2 t2
where t1.name = nvl(v_name, t1.name)
and t1.country = nvl(v_country, t1.country)
and t1.id = t2.id
and t2.type = nvl(v_type, t2.type)
open c1 for l_sql using v_name, v_country;
一个名为type?的列。。。不要问(非常感谢这一点,看起来我必须这样做。对于数量有限的参数,我认为这是最好的解决方案。动态方法更通用,但也需要更多的处理,更难维护。这可能会导致Oracle生成错误的计划。请记住,此语句将有一个计划。它是g如果在t2.type或t1.name上使用任何索引时遇到问题,这可能是SQL注入错误,具体取决于“构建查询”的含义