これがPostgresで可能かどうか疑問に思っています:
不自然な例を使用して最もよく説明されます:
create or replace function test_function(filter_param1 varchar default null
, filter_param2 varchar default null)
returns integer as
$$
declare
stmt text;
args varchar[];
wher varchar[];
retid integer;
begin
if filter_param1 is not null then
array_append(args, filter_param1);
array_append(wher, 'parameter_name = $1');
end if;
if filter_param2 is not null then
array_append(args, filter_param2);
array_append(wher, 'parameter_name = $2');
end if;
stmt := 'select id from mytable where ' || array_to_string(wher, ' or ');
execute stmt into retid using args;
return retid;
end;
$$ language plpgsql;
Pythonには*args
-おそらくPostgreSQLにも同様のメカニズムがありますか?
Erwin Brandstetterの質問の編集:
filter
パラメータは異なる列に適用されますが、ANDする必要があります。setof
を返すことは、ここではずっと意味があります。varchar
)にすることができます。どちらの方法でも、すべてのパラメーターが同じデータ型であるとすれば、それは完全に可能です。
EXECUTE ... USING
喜んで配列を取り、これはsingle引数として扱われます。配列の添え字を持つ要素にアクセスします。
create or replace function test_function(_filter1 text = null
, _filter2 text = null
, OUT retid int) as
$func$
declare
_args text[] := ARRAY[_filter1, _filter2];
_wher text[];
begin
if _filter1 is not null then
_wher := _wher || 'parameter_name = $1[1]'; -- note array subscript
end if;
if _filter2 is not null then
_wher := _wher || 'parameter_name = $1[2]'; -- assign the result!
end if;
IF _args IS NULL -- check whether all params are NULL
RAISE EXCEPTION 'At least one parameter required!';
END IF;
execute 'select id from mytable where ' -- cover case with all params NULL
|| array_to_string(_wher, ' or ')
|| ' ORDER BY id LIMIT 1'; -- For a single value (???)
into retid
using _args;
end
$func$ language plpgsql;
これは単なる概念実証であり、不必要に複雑です。これは、たとえば VARIADIC
function を使用した、 actual 配列入力の興味深いオプションになります。
目下のケースでは、代わりに使用:
CREATE OR REPLACE FUNCTION test_function(_filter1 text = null
, _filter2 text = null)
RETURNS SETOF int AS
$func$
DECLARE
_wher text := concat_ws(' OR '
, CASE WHEN _filter1 IS NOT NULL THEN 'parameter_name = $1' END
, CASE WHEN _filter2 IS NOT NULL THEN 'parameter_name = $2' END);
BEGIN
IF _wher = '' -- check whether all params are NULL
RAISE EXCEPTION 'At least one parameter required!';
END IF;
RETURN QUERY EXECUTE 'SELECT id FROM mytable WHERE ' || _wher
USING $1, $2;
-- USING _filter1 , filter2; -- alternatively use func param names
END
$func$ LANGUAGE plpgsql;
動的クエリで参照される可能性のあるすべての値をUSING
句の出現順にリストします。それらのすべてが動的クエリで参照されない場合でも、害はありません。ただし、通常の位置をそのまま維持する必要があります。
特に、動的クエリ内の$n
は、USING
句の指定された値を序数で参照しますが、-$n
USING
句は、関数パラメーターを参照します。同じ構文、異なるスコープ!
私の例では、単純化のために$2
は$2
を参照しています。ただし、USING
句の値を任意の方法で並べ替えることができるため、(たとえば)動的クエリの$2
は、USING
句の2番目の位置にある$1
を参照します。パラメータ。
これにより、 any any (heterogeneous)data typesのパラメータ数が可能になります。
この例では整数のセットを返します(RETURNS SETOF int
)。これは例に適しています。それに応じて RETURN QUERY EXECUTE
を使用します。
concat_ws()
は、条件付きでORまたはANDされた述語のリストを組み立てるのに特に便利です。