问题
I'm passing 2 parameters to a PL/pgSQL function. Here's the query:
SELECT *
FROM table
WHERE col1 = param1
AND col2 = param2
Both parameters can be NULL, in which case the respective expression should be removed from the WHERE clause.
How can I do that? With IF conditions?
回答1:
Maybe this is doing the trick:
SELECT *
FROM table
WHERE col1 = param1
AND (param2 is null or col2 = param2);
This is not removing the AND condition, but should make the unimportant in case of param2 is null. So not clearly answering your question but going around... ;)
回答2:
A simple (param1 IS NULL OR col1 = param1) takes care of this, as has been answered already.
To actually remove any or all NULL conditions, you need dynamic SQL. You can build your statement in the client conditionally or you can create a plpgsql (or any other procedural language) function to take care of it. This approach may result in superior query plans when dealing with complex queries.
PL/pgSQL function
The tricky parts are:
- to deal with NULL values and empty strings properly in string concatenation
- to deal with variable data types while avoiding possible SQL injection
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;
Three examples for function call:
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.
You need to have a basic understanding of plpgsql for this. You'll find plenty of examples with ample explanation in the plpgsql tag.
回答3:
The simplest (though probably not the most efficient) way is to handle the null inside the SQL statement itself, e.g.:
SELECT *
FROM table
WHERE col1 = param1
AND (param2 IS NULL OR col2 = param2)
This by-passes the clause for all rows if the parameter is null.
Or with this trick:
SELECT *
FROM table
WHERE col1 = param1
AND col2 = COALESCE(param2, col2)
When param2 is NULL, the condition is equivalent to col2 = col2, which will always be true as long as col2 doesn't itself contain NULL values.
A quick test using hard-coded values rather than a function parameter gave me the same query plan for both approaches - the OR and COALESCE parts are seemingly optimised away before planning the query, so it's as though the second AND were indeed being conditionally removed.
来源:https://stackoverflow.com/questions/23386078/how-to-remove-conditions-from-where-clause-if-parameters-are-null