Detta fungerar:
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;
Ring:
SELECT * FROM avg_purchases('{foo,Bar,baz,"}weird_name''$$"}');
Eller (uppdatering - exempel med dollarnotering):
SELECT * FROM avg_purchases($x${foo,Bar,baz,"}weird_name'$$"}$x$);
-
Mer om hur man citerar bokstavliga strängar:
Infoga text med enstaka citattecken i PostgreSQL -
Du behöver inte dynamisk SQL här.
-
Medan du kan linda in det i en plpgsql-funktion (vilket kan vara användbart), en enkel SQL-funktion gör jobbet bra.
-
Du har felmatchningar .
- resultatet av
avg()
kan varanumeric
för att hålla ett exakt resultat. Jag castar tillfloat8
för att få det att fungera, vilket bara är ett alias fördouble precision
(du kan använda antingen). Om du behöver perfekt precision, användnumeric
istället. - Eftersom du
GROUP BY last_name
du vill ha en vanligtext
OUT-parameter istället förtext[]
.
- resultatet av
VARIADIC
En array är en användbar typ av indata. Om det är lättare för din klient kan du också använda en VARIADIC
indataparameter som gör det möjligt att skicka arrayen som en lista med element :
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;
Ring:
SELECT * FROM avg_purchases('foo', 'Bar', 'baz', '"}weird_name''$$"}');
Eller (med dollarnotering):
SELECT * FROM avg_purchases('foo', 'Bar', 'baz', $y$'"}weird_name'$$"}$y$);
Var medveten om att standard Postgres endast tillåter max 100 element . Detta bestäms vid kompilering av det förinställda alternativet:
max_function_args (integer)
Rapporterar det maximala antalet funktionsargument. Det bestäms av värdet på
FUNC_MAX_ARGS
när du bygger servern. Standardvärdet är 100 argument.
Du kan fortfarande kalla det med arraynotation när det är prefixet med nyckelordet VARIADIC
:
SELECT * FROM avg_purchases(VARIADIC '{1,2,3, ... 99,100,101}');
För större arrayer (100+) skulle jag också använda unnest()
i en underfråga och JOIN
till det, som tenderar att skala bättre:
- Optimera en Postgres-fråga med ett stort IN