Toto funguje:
CREATE OR REPLACE FUNCTION avg_purchases(last_names text[] = '{}')
RETURNS TABLE(last_name text, avg_purchase_size float8) AS
$func$
SELECT last_name, AVG(purchase_size)::float8
FROM purchases
WHERE last_name = ANY($1)
GROUP BY last_name
$func$ LANGUAGE sql;
Volejte:
SELECT * FROM avg_purchases('{foo,Bar,baz,"}weird_name''$$"}');
Nebo (aktualizace – příklad s uvedením dolaru):
SELECT * FROM avg_purchases($x${foo,Bar,baz,"}weird_name'$$"}$x$);
-
Více o tom, jak citovat řetězcové literály:
Vložit text s jednoduchými uvozovkami v PostgreSQL -
Zde nepotřebujete dynamické SQL.
-
Zatímco můžete zabalte to do funkce plpgsql (což může být užitečné), jednoduchá funkce SQL to dělá dobře.
-
Máte neshody typu .
- výsledek
avg()
může býtnumeric
udržet přesný výsledek. Odesílám dofloat8
aby to fungovalo, což je jen alias prodouble precision
(můžete použít obojí). Pokud potřebujete dokonalou přesnost, použijtenumeric
místo toho. - Vzhledem k tomu, že
GROUP BY last_name
chcete prostýtext
Parametr OUT namístotext[]
.
- výsledek
VARIADIC
Pole je užitečný typ vstupu. Pokud je to pro vašeho klienta jednodušší, můžete také použít VARIADIC
vstupní parametr, který umožňuje předat pole jako seznam prvků :
CREATE OR REPLACE FUNCTION avg_purchases(VARIADIC last_names text[] = '{}')
RETURNS TABLE(last_name text, avg_purchase_size float8) AS
$func$
SELECT last_name, AVG(purchase_size)::float8
FROM purchases
JOIN (SELECT unnest($1)) t(last_name) USING (last_name)
GROUP BY last_name
$func$ LANGUAGE sql;
Volejte:
SELECT * FROM avg_purchases('foo', 'Bar', 'baz', '"}weird_name''$$"}');
Nebo (s dolarem):
SELECT * FROM avg_purchases('foo', 'Bar', 'baz', $y$'"}weird_name'$$"}$y$);
Uvědomte si, že standardní Postgres povoluje pouze maximálně 100 prvků . To je určeno v době kompilace přednastavenou možností:
max_function_args (integer)
Hlásí maximální počet argumentů funkce. Je určena hodnotou
FUNC_MAX_ARGS
při stavbě serveru. Výchozí hodnota je 100 argumentů.
Stále jej můžete volat pomocí zápisu pole, když je předponou klíčové slovo VARIADIC
:
SELECT * FROM avg_purchases(VARIADIC '{1,2,3, ... 99,100,101}');
Pro větší pole (100+) bych také použil unnest()
v dílčím dotazu a JOIN
k tomu, který má tendenci se lépe škálovat:
- Optimalizace dotazu Postgres s velkým IN