在包含空搜索的where子句中使用函数

时间:2012-01-27 17:39:17

标签: sql oracle

我目前在Java中有一个准备好的语句,它在我的查询的WHERE子句中使用了以下SQL语句,但是我想将它重写为一个函数来限制传递给它的用户参数,并可能使它更多高效。

(
  (USER_PARAM2 IS NULL AND 
    ( COLUMN_NAME = nvl(USER_PARAM1, COLUMN_NAME) OR 
      (nvl(USER_PARAM1, COLUMN_NAME) IS NULL)
    )
  ) 
  OR 
  (USER_PARAM2 IS NOT NULL AND COLUMN_NAME IS NULL)
)

USER_PARAM1和USER_PARAM2由用户传递到准备好的语句中。 USER_PARAM1表示应用程序用户想要搜索此特定COLUMN_NAME的内容。如果用户不包含此参数,则默认为NULL。 USER_PARAM2是我允许用户仅在此COLUMN_NAME上请求NULL值搜索的方法。另外,我有一些服务器逻辑,如果用户传入,则将USER_PARAM2设置为“true”,如果用户未指定,则设置为NULL。

预期的行为是,如果声明了USER_PARAM2,则仅返回NULL的COLUMN_NAME值。如果未声明USER_PARAM2且声明了USER_PARAM1,则仅返回COLUMN_NAME = USER_PARAM1。如果既未声明用户参数,则返回所有行。

有人可以帮我解决这个问题吗? 提前谢谢......

编辑: 只是为了澄清这是我当前查询的外观(没有其他WHERE子句语句..)

SELECT * 
FROM TABLE_NAME
WHERE (
  (USER_PARAM2 IS NULL AND 
    ( COLUMN_NAME = nvl(USER_PARAM1, COLUMN_NAME) OR 
      (nvl(USER_PARAM1, COLUMN_NAME) IS NULL)
    )
  ) 
  OR 
  (USER_PARAM2 IS NOT NULL AND COLUMN_NAME IS NULL)
)

......这就是我想去的地方......

SELECT *
FROM TABLE_NAME
WHERE customSearchFunction(USER_PARAM1, USER_PARAM2, COLUMN_NAME)
编辑#2:编辑#2: 好的,所以另一位同事帮我解决了这个问题......

CREATE OR REPLACE function searchNumber (pVal IN NUMBER, onlySearchForNull IN CHAR, column_value IN NUMBER)
  RETURN NUMBER
IS
BEGIN
  IF onlySearchForNull IS NULL THEN 
    IF pVal IS NULL THEN
      RETURN 1;
    ELSE
      IF pVal = column_value THEN
        RETURN 1;
      ELSE
        RETURN 0;
      END IF;  
    END IF;  
  ELSE 
    IF column_value IS NULL THEN
      RETURN 1;
    ELSE
      RETURN 0;
    END IF;  
  END IF;
END;

......这似乎适用于我最初的试验..

SELECT * 
FROM TABLE_NAME
WHERE 1=searchNumber(USER_PARAM1, USER_PARAM2, COLUMN_NAME);

...我遇到的唯一问题就是 1)可能的性能问题与我开始时的复杂SQL语句有关。 2)我必须为每种数据类型创建类似的功能。 但是,后者对我来说不是一个问题。

编辑#3 2012.02.01

所以我们最终选择了下面选择的解决方案,同时使用基于函数的方法,其中代码/查询清洁度胜过性能。我们发现基于函数的方法比使用纯SQL大约差6倍。

感谢所有人的大力支持!

编辑#4 2012.02.14

回顾过去,我注意到在@Alan的解决方案中应用虚拟表概念和@ danihp解决方案的清晰度,在清晰度和性能方面提供了非常好的整体解决方案。这就是我现在所拥有的

WITH   params AS (SELECT user_param1 AS param, user_param2 AS param_nullsOnly FROM DUAL)
SELECT *
FROM   table_name, params p
WHERE  ( nvl(p.param_nullsOnly, p.param) IS NULL                  --1)
         OR p.param_nullsOnly IS NOT NULL AND column_name IS NULL --2)
         OR p.param IS NOT NULL AND column_name = p.param         --3)
       )
-- 1) Test if all rows should be returned
-- 2) Test if only NULL values should be returned
-- 3) Test if param equals the column value

再次感谢您的建议和意见!

2 个答案:

答案 0 :(得分:2)

我不知道我的方法是否具有更高的性能,但它具有最佳的可读性:

发送2个附加参数进行查询,您可以重写查询,如:

where
( P_ALL_RESULTS is not null
  OR
  P_ONLY_NULLS is not null AND COLUMN_NAME IS NULL
  OR
  P_USE_P1 is not null AND COLUMN_NAME = USER_PARAM1
)

免责声明:在OP问题澄清之前回答

答案 1 :(得分:2)

使用公用表表达式,只需一次传递参数并根据需要多次引用它们的简单方法:

WITH params AS (SELECT user_param1 AS up1, user_param2 AS up2 FROM DUAL)
SELECT *
FROM   table_name, params p
WHERE  ((p.up2 IS NULL 
         AND (column_name = NVL(p.up1, column_name) 
              OR (NVL(p.up1, column_name) IS NULL)))
        OR (p.up2 IS NOT NULL AND column_name IS NULL))

实际上,您正在创建一个虚拟表,其中列是您的参数,用一行填充。

方便地,这也确保您的所有参数都收集在同一个地方,并且可以按任意顺序指定(而不是自然出现在查询中的顺序)。

与基于功能的方法相比,这有很多优点。首先,这不会阻止索引的使用(如@Bob Jarvis所指出的)。其次,这会将查询的逻辑保留在查询中,而不是隐藏在函数中。