PL/SQL查询中的空值问题
Posted
技术标签:
【中文标题】PL/SQL查询中的空值问题【英文标题】:PL/SQL null value problem in query 【发布时间】:2011-07-07 07:18:27 【问题描述】:我必须创建一个带有七个输入参数的 pl/sql 函数。
问题是用户可以以任意组合传递这些参数中的任何一个,以使其余参数为空。因此,多种组合是可能的。而且我必须在删除空参数后使用这些参数查询一个表。
有没有办法在不使用嵌套 if 数量检查空值的情况下做到这一点?
【问题讨论】:
【参考方案1】:还包括在 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。
【讨论】:
【参考方案2】:一种解决方案是在 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
注意:无参数 = 所有结果
【讨论】:
+1 在这种情况下我更喜欢这样做。另一种方法是动态 sql,但我认为这有点混乱,并没有从编译检查中受益。 我同意动态 sql 也可能更难维护和调试。 如果其中一个参数为空,则此查询不返回任何内容 很好,已经将 AND 更改为 OR...但是短循环逻辑是重要的一点 哈哈没有正确阅读正确的方法是(col = param或param为null)它应该没有参数=所有结果:)但这可能不是op想要的【参考方案3】:你可以使用
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;
此版本将酌情使用表上的索引,并且对于每个唯一的“无效”参数组合仍然只能获得一次硬解析。
两个动态版本的缺点是你没有得到编译时语法检查。
【讨论】:
我已经尝试了两种简短的curcuit方法和都使用索引, 但是您在建议的解决方案中回答了不同的问题。您的回答意味着每个参数都不为空。否则它什么也不返回。问题 IMO 要求 null 参数意味着不应按适当的列过滤结果集。 您的两个答案似乎都是正确的,但现在我选择第一个。我必须检查是否存在与性能相关的问题。感谢帮助。只想问一个问题,如果要返回多行,返回refcursor是否可以。 当然,这就是 ref_cursors 的初衷。【参考方案4】:您可以使用以下内容:
select * from tableA
where col1 = nvl(parameter1, col1)
and ....
【讨论】:
与其他答案中建议的(col1 = parameter1 or parameter1 is null)
相比,这如何更好?我看到这个表格被提到很多次了,但是有什么好处呢?此外,如果 col1 可以为空,则此表单无法正常工作。以上是关于PL/SQL查询中的空值问题的主要内容,如果未能解决你的问题,请参考以下文章