我将2个参数传递给PL / pgSQL函数。这是查询:
SELECT *
FROM table
WHERE col1 = param1
AND col2 = param2
两个参数都可以为NULL,在这种情况下,应从WHERE
子句中删除相应的表达式。
我该怎么做?有IF
条件吗?
答案 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(或任何其他过程语言)函数来处理它。在处理复杂查询时,这种方法可能会产生出色的查询计划。
棘手的部分是:
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');
您需要对plpgsql有基本的了解。您可以在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)
当param2
为NULL
时,条件相当于col2 = col2
,只要col2
本身不包含{{1},该条件将始终为真值。
使用硬编码值而不是函数参数的快速测试为我提供了两种方法的相同查询计划 - NULL
和OR
部分在规划查询之前似乎已经过优化,因此它和好像第二个COALESCE
确实被有条件地删除了。