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查询中的空值问题的主要内容,如果未能解决你的问题,请参考以下文章

SQL DataReader 如何显示查询中的空值

MS SQL Server 2008 中的空值处理

SQL 查询数据连接具有它忽略的空值

在 SQL 查询中过滤掉由窗口函数 lag() 产生的空值

SQL问题求助,查询结果如何清除NULL的空值

使用mysql中的select语句替换sql中的空值?