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则应该使不重要.所以没有明确回答你的问题,但四处走动......;)
(param1 IS NULL OR col1 = param1)正如已经回答的那样,简单地解决这个问题.
要实际删除任何或所有NULL条件,您需要动态SQL.您可以有条件地在客户端中构建语句,也可以创建plpgsql(或任何其他过程语言)函数来处理它.在处理复杂查询时,此方法可能会产生出色的查询计划.
棘手的部分是:
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)
你需要对plpgsql有一个基本的了解.您可以在plpgsql标记中找到大量有充分解释的示例.
最简单(尽管可能不是最有效)的方法是在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)
当param2是NULL时,条件等同于col2 = col2,这将永远是正确的,只要col2本身不包含NULL值.
使用硬编码值而不是函数参数的快速测试为我提供了两种方法的相同查询计划 - 在计划查询之前,这些OR和COALESCE部分似乎已经被优化掉了,所以就好像第二AND个确实被有条件地删除了一样.