如果参数为NULL,如何从WHERE子句中删除条件

时间:2014-04-30 10:48:33

标签: sql postgresql null plpgsql

我将2个参数传递给PL / pgSQL函数。这是查询:

SELECT * 
FROM table 
WHERE col1 = param1 
  AND col2 = param2

两个参数都可以为NULL,在这种情况下,应从WHERE子句中删除相应的表达式。

我该怎么做?有IF条件吗?

3 个答案:

答案 0 :(得分:11)

也许这就是诀窍:

SELECT * 
FROM table 
WHERE col1 = param1 
  AND (param2 is null or col2 = param2);

这不是删除AND条件,但是如果param2为null则应该使不重要。所以没有清楚地回答你的问题,而是四处走动......;)

答案 1 :(得分:6)

一个简单的(param1 IS NULL OR col1 = param1)会照顾到这一点,正如已经回答的那样。

实际删除任何或所有NULL条件,您需要动态SQL 。您可以有条件地在客户端中构建语句,也可以创建plpgsql(或任何其他过程语言)函数来处理它。在处理复杂查询时,这种方法可能会产生出色的查询计划。

PL/pgSQL功能

棘手的部分是:

  • 在字符串连接中正确处理NULL值和空字符串
  • 处理可变数据类型,同时避免可能的SQL注入

CREATE OR REPLACE FUNCTION f_conditional_where(_param1 int  = NULL
                                             , _param2 text = NULL
                                             , _param3 date = NULL)
  RETURNS SETOF tbl AS
$func$
DECLARE
   _where text :=
      concat_ws(' AND '
        , CASE WHEN _param1 IS NOT NULL THEN 'col1 = $1' END
        , CASE WHEN _param2 IS NOT NULL THEN 'col2 = $2' END
        , CASE WHEN _param3 IS NOT NULL THEN 'col3 = $3' END);   
   _sql text := 'SELECT * FROM tbl';
BEGIN

IF _where <> '' THEN
   _sql := _sql || ' WHERE ' || _where;
END IF;

-- debug output
RAISE NOTICE '
 _sql:   |%|
 _where: |%|', _sql, _where;

-- execute
RETURN QUERY EXECUTE _sql
USING $1, $2, $3;

END
$func$  LANGUAGE plpgsql;

函数调用的三个例子:

SELECT * FROM f_conditional_where();
SELECT * FROM f_conditional_where(1, 'foo');
SELECT * FROM f_conditional_where(_param3 := '2012-01-01', _param2 := 'foo');

SQL Fiddle.

您需要对plpgsql有基本的了解。您可以在标记中找到大量有充分解释的示例。

答案 2 :(得分:5)

最简单(尽管可能不是最有效)的方法是在SQL语句本身内处理null,例如:

SELECT * 
FROM table 
WHERE col1 = param1 
AND (param2 IS NULL OR col2 = param2)

如果参数为null,则绕过所有行的子句。

或者用这个技巧:

SELECT * 
FROM table 
WHERE col1 = param1 
AND col2 = COALESCE(param2, col2)

param2NULL时,条件相当于col2 = col2,只要col2本身不包含{{1},该条件将始终为真值。

使用硬编码值而不是函数参数的快速测试为我提供了两种方法的相同查询计划 - NULLOR部分在规划查询之前似乎已经过优化,因此它和好像第二个COALESCE确实被有条件地删除了。