Din funktion kan se ut så här:
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;
I PostgreSQL 9.1 eller senare är det enklare med format()
...
RETURN QUERY EXECUTE format('
SELECT *
FROM transactions
WHERE %I = $1
LIMIT $2', _col)
USING _val, _limit;
...
%I
undkommer identifierare som quote_ident()
.
Huvudpunkter:
-
Du stötte på begränsningen för dynamisk SQL att du inte kan använda parametrar för identifierare. Du måste bygga frågesträngen med kolumnnamnet och sedan kör det.
-
Du kan dock göra det med värderingar. Jag demonstrerar användningen av
USING
sats förEXECUTE
. Observera också användningen avquote_ident()
:förhindrar SQL-injektion och vissa syntaxfel. -
Jag har också till stor del förenklat din funktion.
[RETURN QUERY EXECUTE][3]
gör din kod kortare och snabbare. Inget behov av loop om allt du gör är att returnera raden. -
Jag använder namnet
IN
parametrar, så att du inte blir förvirrad med $-notationen i frågesträngen.$1
och$2
inuti frågesträngen hänvisar till värdena iUSING
sats, inte till ingångsparametrarna. -
Jag ändrar till
SELECT *
eftersom du måste returnera hela raden för att matcha den deklarerade returtypen ändå. -
Sist men inte minst:Var noga med att tänka på vad manualen har att säga om funktioner som deklareras
SECURITY DEFINER
.
RETURNERINGSTYP
Om du inte vill returnera hela raden är en praktisk möjlighet:
CREATE FUNCTION select_transactions3(_col text, _val text, _limit int)
RETURNS TABLE (invoice_no varchar(125), amount numeric(12,2) AS ...
Då behöver du inte tillhandahålla en kolumndefinitionslista med varje samtal och kan förenkla till:
SELECT * FROM select_to_transactions3('invoice_no', '1103300105472', 1);