Ihre Funktion könnte so aussehen:
CREATE FUNCTION select_transactions3(_col text, _val text, _limit int)
RETURNS SETOF transactions AS
$BODY$
BEGIN
RETURN QUERY EXECUTE '
SELECT *
FROM transactions
WHERE ' || quote_ident(_col) || ' = $1
LIMIT $2'
USING _val, _limit;
END;
$BODY$
LANGUAGE plpgsql VOLATILE SECURITY DEFINER;
IN PostgreSQL 9.1 oder später ist das einfacher mit dem Format format()
...
RETURN QUERY EXECUTE format('
SELECT *
FROM transactions
WHERE %I = $1
LIMIT $2', _col)
USING _val, _limit;
...
%I
maskiert Identifikatoren wie quote_ident()
.
Hauptpunkte:
-
Sie sind auf die Einschränkung von dynamischem SQL gestoßen, dass Sie keine Parameter für Bezeichner verwenden können. Sie müssen den Abfragestring mit dem Spaltennamen und dann aufbauen ausführen.
-
Sie können dies jedoch mit Werten tun. Ich demonstriere die Verwendung von
USING
Klausel fürEXECUTE
. Beachten Sie auch die Verwendung vonquote_ident()
:verhindert SQL-Injection und bestimmte Syntaxfehler. -
Ich habe auch Ihre Funktion stark vereinfacht.
[RETURN QUERY EXECUTE][3]
macht Ihren Code kürzer und schneller. Es ist keine Schleife erforderlich, wenn Sie nur die Zeile zurückgeben. -
Ich verwende den Namen
IN
Parameter, damit Sie nicht mit der $-Notation in der Abfragezeichenfolge verwechselt werden.$1
und$2
innerhalb der Abfragezeichenfolge beziehen sich auf die inUSING
bereitgestellten Werte -Klausel, nicht zu den Eingabeparametern. -
Ich wechsle zu
SELECT *
da Sie sowieso die gesamte Zeile zurückgeben müssen, um mit dem deklarierten Rückgabetyp übereinzustimmen. -
Last but not least:Achten Sie darauf, was das Handbuch zu Funktionen zu sagen hat, die als
SECURITY DEFINER
.
RÜCKGABEART
Wenn Sie nicht die ganze Zeile zurückgeben möchten, gibt es eine bequeme Möglichkeit:
CREATE FUNCTION select_transactions3(_col text, _val text, _limit int)
RETURNS TABLE (invoice_no varchar(125), amount numeric(12,2) AS ...
Dann müssen Sie nicht bei jedem Aufruf eine Spaltendefinitionsliste angeben und können vereinfachen zu:
SELECT * FROM select_to_transactions3('invoice_no', '1103300105472', 1);