【发布时间】:2011-07-07 07:18:27
【问题描述】:
我必须创建一个带有七个输入参数的 pl/sql 函数。
问题是用户可以以任意组合传递这些参数中的任何一个,以使其余参数为空。因此,多种组合是可能的。而且我必须在删除空参数后使用这些参数查询一个表。
有没有办法在不使用嵌套 if 数量检查空值的情况下做到这一点?
【问题讨论】:
我必须创建一个带有七个输入参数的 pl/sql 函数。
问题是用户可以以任意组合传递这些参数中的任何一个,以使其余参数为空。因此,多种组合是可能的。而且我必须在删除空参数后使用这些参数查询一个表。
有没有办法在不使用嵌套 if 数量检查空值的情况下做到这一点?
【问题讨论】:
还包括在 WHERE 子句中检查输入参数是否为空
例如,假设输入参数为 parameter1 , parameter2 ,parameter3
select * from tableA
where (col1 = parameter1 or parameter1 is null)
and (col2 = parameter2 or parameter2 is null)
and (col3 = parameter3 or parameter3 is null)
如果 parameter1 为 null ,它将始终针对此参数的条件返回 true。
【讨论】:
一种解决方案是在 where 子句中使用逻辑来缩短条件
例如:
SELECT blah WHERE (param1 IS NOT NULL AND col1=param1)
OR (param2 IS NOT NULL AND col2=param2) ….etc
注意:没有参数 = 没有结果
或
SELECT blah WHERE (param1 IS NULL OR col1=param1)
AND (param2 IS NULL OR col2=param2) ….etc
注意:无参数 = 所有结果
【讨论】:
你可以使用
select * from table t where
(param1 is null or t.column1 = param1) and
(param2 ....)
但这将不使用表上的任何索引,或者在最坏的情况下使用不合适的索引(由于游标共享,在 11G 之前无法避免。在 11G 中有时可能会起作用但它不是你应该依赖的东西)。
要获得更好的解决方案,您必须使用动态查询。在 PLSQL 中,这在大多数情况下使用 execute immediate l_query; (or open cursor for l_query;) 或通过更强大(但使用起来更复杂)DBMS_SQL(在非常有限的情况下需要)来完成。
更简单(但使用文字,因此几乎在任何时候都需要硬解析)解决方案是
procedure dynamic_query_literals (param1 ... param7)
is
l_query varchar2(1000);
l_cursor sys_refcursor;
begin
l_query := 'select * from table t where 1=1';
if (param1 is not null) then
l_query := l_query || ' and t.column1 = param1';
end if;
if (param2 ...)
open l_cursor for l_query;
-- do whatever needed with the result set in the cursor.
--The procedure can even return this cursor...
end;
更复杂但性能更高(特别是如果此过程被多次调用)解决方案需要绑定参数(当您在 plsql 中使用静态 sql 时会自动且透明地完成)
procedure dynamic_query_binding (param1 ... param7)
is
l_query varchar2(1000);
l_cursor sys_refcursor;
begin
l_query := 'select * from table t where 1=1';
if (param1 is null) then
--this will get optimised away in the process but is required
--syntactically for use of "using" later
l_query := l_query || ' and 1=1 or :param1 is null';
else
l_query := l_query || ' and t.column1 = :param1';
end if;
if (param2 ...)
open l_cursor for l_query
using param1, param2, ... param7;
-- do whatever needed with the result set in the cursor.
-- The procedure can even return this cursor...
end;
此版本将酌情使用表上的索引,并且对于每个唯一的“无效”参数组合仍然只能获得一次硬解析。
两个动态版本的缺点是你没有得到编译时语法检查。
【讨论】:
您可以使用以下内容:
select * from tableA
where col1 = nvl(parameter1, col1)
and ....
【讨论】:
(col1 = parameter1 or parameter1 is null) 相比,这如何更好?我看到这个表格被提到很多次了,但是有什么好处呢?此外,如果 col1 可以为空,则此表单无法正常工作。