【问题标题】:PL/SQL null value problem in queryPL/SQL查询中的空值问题
【发布时间】:2011-07-07 07:18:27
【问题描述】:

我必须创建一个带有七个输入参数的 pl/sql 函数。

问题是用户可以以任意组合传递这些参数中的任何一个,以使其余参数为空。因此,多种组合是可能的。而且我必须在删除空参数后使用这些参数查询一个表。

有没有办法在不使用嵌套 if 数量检查空值的情况下做到这一点?

【问题讨论】:

    标签: sql oracle function plsql


    【解决方案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 可以为空,则此表单无法正常工作。
      猜你喜欢
      • 1970-01-01
      • 2013-03-11
      • 2011-08-22
      • 2012-10-26
      • 2021-02-12
      • 1970-01-01
      • 2013-11-08
      • 2011-11-07
      • 2023-04-01
      相关资源
      最近更新 更多