Ich frage mich, ob dies in Postgres möglich ist:
Am besten anhand eines erfundenen Beispiels erklären:
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;
In Python gibt es *args
- vielleicht hat PostgreSQL einen ähnlichen Mechanismus?
EDIT für Erwin Brandstetter Fragen:
- Alle
filter
Parameter werden auf verschiedene Spalten angewendet, sollten jedoch UND-verknüpft sein. - Die Rückkehr
setof
ist hier viel sinnvoller. - Alle Parameter können vom gleichen Spaltentyp sein (dh
varchar
).
EXECUTE ... USING
ich kann kein Array von Argumenten annehmen, da PostgreSQL-Arrays keine heterogenen Typen unterstützen. Sie müssen ein Array eines einzelnen konkreten Typs sein, und SQL hat möglicherweise nicht für jeden Parameter den gleichen Typ. Es wäre nutzlos, außer für sehr enge Anwendungsfälle. StattdessenUSING
müsste in der Lage sein, einen anonymen Datensatz zu erstellen, wie Sie ihn von einemROW(...)
Konstruktor erstellen ... was wahrscheinlich möglich, aber derzeit nicht implementiert ist.parameter_name
? (Das könnte weitgehend vereinfacht werden.) Oder denken Sie wirklich an verschiedene Spalten? Möchten Sie einen einzelnen Wert oder eine Reihe von Werten zurückgeben? Eine Reihe von OR-Prädikaten gibt normalerweise mehrere Zeilen zurück, was nicht zu IhrerRETURNS
Klausel passt .Antworten:
In beiden Fällen ist dies durchaus möglich , da alle Ihre Parameter vom gleichen Datentyp sind .
EXECUTE ... USING
nimmt gerne ein Array, das als einzelnes Argument behandelt wird. Greifen Sie auf Elemente mit Array-Indizes zu.Dies ist nur ein Proof of Concept und unnötig kompliziert. Dies wäre eine interessante Option für die tatsächliche Array-Eingabe, beispielsweise mit einer
VARIADIC
Funktion .Verwenden Sie für den vorliegenden Fall stattdessen:
Erklären
Listen Sie alle Werte, auf die möglicherweise in der dynamischen Abfrage verwiesen werden kann, in der
USING
Klausel in ihrer Reihenfolge auf. Wenn nicht alle in der dynamischen Abfrage referenziert werden, schadet dies nicht. Aber wir müssen die Ordnungspositionen intakt halten.Beachten Sie insbesondere, dass in der dynamischen Abfrage bestimmte Werte der Klausel nach Ordnungszahl referenziert werden , während in der Klausel auf Funktionsparameter verwiesen wird. Gleiche Syntax, anderer Umfang! In meinem Beispiel Referenzen der Einfachheit halber. Man kann aber die Werte in der Klausel auf jede Art und Weise neu anordnen, so dass (zum Beispiel) in der dynamischen Abfrage auf die 2. Position in der Klausel verwiesen wird, die auf den 1. Funktionsparameter verweist.
$n
USING
$n
USING
$2
$2
USING
$2
$1
USING
Dies ermöglicht eine beliebige Anzahl von Parametern mit beliebigen (heterogenen) Datentypen .
Rückgabe einer Ganzzahl in diesem Beispiel (
RETURNS SETOF int
), die besser zum Beispiel passt -RETURN QUERY EXECUTE
entsprechend verwenden.concat_ws()
ist besonders praktisch, um eine Liste von ODER- oder UND-Prädikaten unter bestimmten Bedingungen zusammenzustellen.quelle
USING
Klausel angegebene Argumente können 0-n-mal referenziert werden. Es ist nicht genau das gleiche Konzept wie*args
in Python, es ist tatsächlich flexibler.quelle