我正在尝试编写一个函数,根据提供的参数有条件地删除数据。我希望能够使用默认参数,这样如果没有明确提供它们,该函数就不会进行任何过滤。两种过滤类型中的第一种是时间范围,第二种是主键数组。
对于时间范围,我可以使用默认的哨兵变量+/- infinity
。这匹配所有数据,实质上禁用过滤器。这些由 postgres 提供。有什么东西(某种哨兵)可以用来禁用基于数组的过滤器吗?
具体来说,我会向函数传递一个整数数组,但我想默认禁用此过滤器(即,当我不传递数组时)。显而易见的选择是将数组设置为空数组作为默认参数。但是,where in
空数组将不匹配任何内容(假设空数组甚至是有效的 plpgql)。所以显而易见的选择是有一个IF
语句,或者动态 SQL。但是知道 postgres 必须有一些我可能错过的技巧或语法。
编辑:
我最初的计划是编写一个布尔 UDF 来模拟我想要的行为。类似的东西:
CREATE OR REPLACE FUNCTION filter_category(
category_array INTEGER[],
current_category INTEGER
)
RETURNS
BOOLEAN AS $$
BEGIN
IF category_array = '{}' THEN
RETURN TRUE;
ELSE
-- if in set return true, else false.
RETURN FALSE;
END IF;
END;
$$ LANGUAGE plpgsql;
但是,经过对此事的进一步思考,我认为查询将不得不变得更加复杂。一个where in array
子句或上面的函数可能不会很有效。因此,要最终使用可能存在的任何索引,我必须取消嵌套主键数组并执行连接。
而且我应该只在数组不为空时才这样做。所以查询将需要至少一个 `IF ... ELSE... END IF' 语句。如果我需要进一步过滤,我可能必须实现中间本地数据集。我仍然对任何建议感兴趣:D
编辑2:
我的动态查询如下所示:
CREATE OR REPLACE FUNCTION get_paginated_search_results(
forum_id_ INTEGER,
query_ CHARACTER VARYING,
from_date_ TIMESTAMP WITHOUT TIME ZONE DEFAULT NULL,
to_date_ TIMESTAMP WITHOUT TIME ZONE DEFAULT NULL,
in_categories_ INTEGER[] DEFAULT '{}')
RETURNS SETOF post_result_entry AS $$
DECLARE
join_string CHARACTER VARYING := ' ';
from_where_date CHARACTER VARYING := ' ';
to_where_date CHARACTER VARYING := ' ';
query_string_ CHARACTER VARYING := ' ';
BEGIN
IF NOT from_date_ IS NULL THEN
from_where_date := ' AND fp.posted_at > ''' || from_date_ || '''';
END IF;
IF NOT to_date_ IS NULL THEN
to_where_date := ' AND fp.posted_at < ''' || to_date_ || '''';
END IF;
CREATE LOCAL TEMP TABLE un_cat(id) ON COMMIT DROP AS (select * from unnest(in_categories_)) ;
if in_categories_ != '{}' THEN
join_string := ' INNER JOIN forum_topics ft ON fp.topic_id = ft.id ' ||
' INNER JOIN un_cat uc ON uc.id = ft.category_id ' ;
END IF;
query_string_ := '
SELECT index,posted_at,post_text,name,join_date,quotes
FROM forum_posts fp
INNER JOIN forum_user fu ON
fu.forum_id = fp.forum_id AND fu.id = fp.user_id' ||
join_string
||
'WHERE fu.forum_id = ' || forum_id_ || ' AND
to_tsvector(''english'',fp.post_text) @@ to_tsquery(''english'','''|| query_||''')' ||
from_where_date ||
to_where_date
||';';
RAISE NOTICE '%', query_string_ ;
RETURN QUERY
EXECUTE query_string_;
END;
$$ LANGUAGE plpgsql;