To działa:
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;
Zadzwoń:
SELECT * FROM avg_purchases('{foo,Bar,baz,"}weird_name''$$"}');
Lub (aktualizacja - przykład z cytatem w dolarach):
SELECT * FROM avg_purchases($x${foo,Bar,baz,"}weird_name'$$"}$x$);
-
Więcej informacji o cytowaniu literałów ciągu:
Wstaw tekst z pojedynczymi cudzysłowami w PostgreSQL -
Nie potrzebujesz tutaj dynamicznego SQL.
-
Chociaż możesz zapakuj go w funkcję plpgsql (co może być przydatne), prosta funkcja SQL wykonuje to zadanie dobrze.
-
Masz niezgodności typów .
- wynik
avg()
może byćnumeric
aby uzyskać dokładny wynik. Przesyłam dofloat8
aby to działało, co jest tylko aliasem dladouble precision
(możesz użyć albo). Jeśli potrzebujesz doskonałej precyzji, użyjnumeric
zamiast tego. - Ponieważ
GROUP BY last_name
chcesz zwykłytext
Parametr OUT zamiasttext[]
.
- wynik
VARIADIC
Tablica jest użytecznym typem danych wejściowych. Jeśli jest to łatwiejsze dla Twojego klienta, możesz również użyć VARIADIC
parametr wejściowy pozwalający na przekazanie tablicy jako listy elementów :
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;
Zadzwoń:
SELECT * FROM avg_purchases('foo', 'Bar', 'baz', '"}weird_name''$$"}');
Lub (z cytatem w dolarach):
SELECT * FROM avg_purchases('foo', 'Bar', 'baz', $y$'"}weird_name'$$"}$y$);
Pamiętaj, że standardowy Postgres zezwala na maksymalnie 100 elementów . Jest to określane w czasie kompilacji przez opcję ustawień wstępnych:
max_function_args (integer)
Podaje maksymalną liczbę argumentów funkcji. Określa ją wartość FUNC_MAX_ARGS
podczas budowania serwera. Domyślna wartość to 100 argumentów.
Nadal można go wywoływać za pomocą notacji tablicowej, jeśli jest poprzedzony słowem kluczowym VARIADIC
:
SELECT * FROM avg_purchases(VARIADIC '{1,2,3, ... 99,100,101}');
W przypadku większych tablic (100+) użyłbym również unnest()
w podzapytaniu i JOIN
do niego, co ma tendencję do lepszego skalowania:
- Optymalizacja zapytania Postgres z dużym IN