Isso funciona:
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;
Ligar:
SELECT * FROM avg_purchases('{foo,Bar,baz,"}weird_name''$$"}');
Ou (atualização - exemplo com cotação do dólar):
SELECT * FROM avg_purchases($x${foo,Bar,baz,"}weird_name'$$"}$x$);
-
Mais sobre como citar literais de string:
Inserir texto com aspas simples no PostgreSQL
-
Você não precisa de SQL dinâmico aqui.
-
Enquanto você pode envolvê-lo em uma função plpgsql (que pode ser útil), uma função SQL simples está fazendo o trabalho muito bem.
-
Você tem incompatibilidades de tipo .
- o resultado de
avg()
pode sernumeric
para manter um resultado preciso. Transmito parafloat8
para fazê-lo funcionar, que é apenas um alias paradouble precision
(você pode usar qualquer um). Se você precisa de precisão perfeita, usenumeric
em vez disso. - Desde que você
GROUP BY last_name
você quer umtext
simples Parâmetro OUT em vez detext[]
.
- o resultado de
VARIADIC
Uma matriz é um tipo útil de entrada. Se for mais fácil para o seu cliente, você também pode usar um
VARIADIC
parâmetro de entrada que permite passar o array como uma lista de elementos :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;
Ligar:
SELECT * FROM avg_purchases('foo', 'Bar', 'baz', '"}weird_name''$$"}');
Ou (com cotação do dólar):
SELECT * FROM avg_purchases('foo', 'Bar', 'baz', $y$'"}weird_name'$$"}$y$);
Esteja ciente de que o Postgres padrão permite apenas um máximo de 100 elementos . Isso é determinado em tempo de compilação pela opção predefinida:
max_function_args (integer)
Informa o número máximo de argumentos de função. É determinado pelo valor deFUNC_MAX_ARGS
ao construir o servidor. O valor padrão é 100 argumentos.
Você ainda pode chamá-lo com notação de array quando prefixado com a palavra-chave
VARIADIC
:SELECT * FROM avg_purchases(VARIADIC '{1,2,3, ... 99,100,101}');
Para matrizes maiores (mais de 100), eu também usaria
unnest()
em uma subconsulta e JOIN
para ele, que tende a escalar melhor:- Otimizando uma consulta Postgres com um grande IN