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

use*_*988 3 sql postgresql null plpgsql

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

SELECT * 
FROM table 
WHERE col1 = param1 
  AND col2 = param2
Run Code Online (Sandbox Code Playgroud)

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

我怎样才能做到这一点?随着IF条件是什么?

frl*_*lan 11

也许这就是诀窍:

SELECT * 
FROM table 
WHERE col1 = param1 
  AND (param2 is null or col2 = param2);
Run Code Online (Sandbox Code Playgroud)

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


Erw*_*ter 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;
Run Code Online (Sandbox Code Playgroud)

函数调用的三个例子:

SELECT * FROM f_conditional_where();
SELECT * FROM f_conditional_where(1, 'foo');
SELECT * FROM f_conditional_where(_param3 := '2012-01-01', _param2 := 'foo');
Run Code Online (Sandbox Code Playgroud)

SQL小提琴.

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


IMS*_*SoP 5

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

SELECT * 
FROM table 
WHERE col1 = param1 
AND (param2 IS NULL OR col2 = param2)
Run Code Online (Sandbox Code Playgroud)

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

或者用这个技巧:

SELECT * 
FROM table 
WHERE col1 = param1 
AND col2 = COALESCE(param2, col2)
Run Code Online (Sandbox Code Playgroud)

param2NULL时,条件等同于col2 = col2,这将永远是正确的,只要col2本身不包含NULL值.

使用硬编码值而不是函数参数的快速测试为我提供了两种方法的相同查询计划 - 在计划查询之前,这些ORCOALESCE部分似乎已经被优化掉了,所以就好像第二AND个确实被有条件地删除了一样.

  • 实际上,`col2 = col2`并不总是正确的.如果`col2`可以包含空值,这个条件可能是`unknown`,所以这个方法不仅不会使用索引,而且还会返回错误的结果 (4认同)