Oracle PL\SQL Null输入参数WHERE条件

Ase*_*tam 5 oracle plsql

截至目前,我正在使用IF ELSE来处理这种情况

IF INPUT_PARAM IS NOT NULL

    SELECT ... FROM SOMETABLE WHERE COLUMN = INPUT_PARAM
ELSE
    SELECT ... FROM SOMETABLE
Run Code Online (Sandbox Code Playgroud)

有没有更好的方法在没有IF ELSE循环的单个查询中执行此操作.随着查询变得复杂,会有更多这样的输入参数,并且所需的IF ELSE数量太多.

Vin*_*rat 9

一种方法是使用的变体

 WHERE column = nvl(var, column)
Run Code Online (Sandbox Code Playgroud)

然而,这里有两个陷阱:

  1. 如果列可以为空,则此子句将过滤空值,而在您的问题中,您不会在第二种情况下过滤空值.您可以修改此子句以将空值考虑在内但它变得丑陋:

        WHERE nvl(column, impossible_value) = nvl(var, impossible_value)
    
    Run Code Online (Sandbox Code Playgroud)

    当然,如果以某种方式impossible_value插入,你将遇到其他一些(有趣的)问题.

  2. 优化器无法正确理解这种类型的子句.它有时会生成一个带有UNION ALL的计划,但是如果有多个nvl,那么即使存在完全有效的索引,您也将获得完整扫描.

这就是为什么当有很多参数(例如大型搜索字段)时,我喜欢使用动态SQL:

DECLARE
   l_query VARCHAR2(32767) := 'SELECT ... JOIN ... WHERE 1 = 1';
BEGIN
   IF param1 IS NOT NULL THEN
      l_query := l_query || ' AND column1 = :p1';
   ELSE 
      l_query := l_query || ' AND :p1 IS NULL';
   END IF;
   /* repeat for each parameter */
   ...
   /* open the cursor dynamically */
   OPEN your_ref_cursor FOR l_query USING param1 /*,param2...*/; 
END;
Run Code Online (Sandbox Code Playgroud)

你也可以使用 EXECUTE IMMEDIATE l_query INTO l_result USING param1;