How to remove conditions from WHERE clause if parameters are NULL

ⅰ亾dé卋堺 提交于 2019-12-05 02:15:24

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!