Uw functie kan er als volgt uitzien:
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 of later is dat eenvoudiger met format()
...
RETURN QUERY EXECUTE format('
SELECT *
FROM transactions
WHERE %I = $1
LIMIT $2', _col)
USING _val, _limit;
...
%I
ontsnapt aan identifiers zoals quote_ident()
.
Belangrijkste punten:
-
U liep tegen de beperking van dynamische SQL aan dat u geen parameters voor id's kunt gebruiken. U moet de queryreeks bouwen met de kolomnaam en vervolgens voer het uit.
-
Dat kun je wel doen met waarden. Ik demonstreer het gebruik van de
USING
clausule voorEXECUTE
. Let ook op het gebruik vanquote_ident()
:voorkomt SQL-injectie en bepaalde syntaxisfouten. -
Ik heb je functie ook grotendeels vereenvoudigd.
[RETURN QUERY EXECUTE][3]
maakt je code korter en sneller. U hoeft niet te herhalen als u alleen de rij terugstuurt. -
Ik gebruik de naam
IN
parameters, zodat u niet in de war raakt met de $-notatie in de queryreeks.$1
en$2
verwijzen in de queryreeks naar de waarden in deUSING
clausule, niet naar de invoerparameters. -
Ik verander naar
SELECT *
omdat je toch de hele rij moet retourneren om overeen te komen met het opgegeven retourtype. -
Last but not least:denk goed na wat de handleiding te zeggen heeft over functies die zijn gedeclareerd
SECURITY DEFINER
.
RETOURTYPE
Als u niet de hele rij wilt retourneren, is een handige mogelijkheid:
CREATE FUNCTION select_transactions3(_col text, _val text, _limit int)
RETURNS TABLE (invoice_no varchar(125), amount numeric(12,2) AS ...
Dan hoeft u niet bij elke oproep een kolomdefinitielijst te verstrekken en kunt u vereenvoudigen tot:
SELECT * FROM select_to_transactions3('invoice_no', '1103300105472', 1);