Appeler une fonction set-returning avec un argument array plusieurs fois
c'est une variation sur la fonction plpgsql qui retourne plusieurs colonnes est appelée plusieurs fois . Cependant, j'espérais trouver une solution à mes circonstances particulières.
j'ai une fonction qui traite d'un tableau de lignes avec un paramètre donné, et retourne un ensemble de lignes + une nouvelle colonne.
CREATE OR REPLACE foo(data data[], parameter int) RETURNS SETOF enhanceddata AS
...
la fonction fonctionne sur un cas d'essai avec seulement 1 jeu de données
SELECT * FROM foo( (SELECT ARRAY_AGG(data) FROM datatable GROUP BY dataid WHERE dataid = something), 1)
mais je voudrais le faire fonctionner avec plusieurs groupes de données, sans passer un dataid
à la fonction. J'ai essayé un certain nombre de variantes de:
SELECT dataid, (foo(ARRAY_AGG(data)),1).*
FROM dataset
WHERE dataid = something -- only testing on 1
GROUP BY dataid
, Mais la fonction est appelée une fois pour chaque colonne.
2 réponses
dans Postgres 9.3 ou plus tard, il est préférable d'utiliser ( LEFT
) JOIN LATERAL
.
SELECT sub.dataid, f.*
FROM (
SELECT dataid, array_agg(data) AS arr
FROM dataset
WHERE dataid = something
GROUP BY 1
) sub
LEFT JOIN LATERAL foo(sub.arr) f ON true;
si la fonction foo()
peut retourner pas de lignes , la forme sûre est avec LEFT JOIN LATERAL
comme démontré. Sinon, ou si vous voulez exclure des lignes sans résultat de la jointure latérale, utilisez JOIN LATERAL
ou son équivalent en sténo:
, foo(sub.arr)
ceci est mentionné explicitement dans le manuel.
j'ai mis à jour la réponse connexe de Craig (mentionnée par Daniel) en conséquence:
la fonction est appelée plusieurs fois dans ce contexte non pas à cause de ses entrées, mais à cause de la façon dont func().*
est implémentée
cela est expliqué à: Comment éviter les évaluations de fonctions multiples avec le (func()).* syntaxe dans une requête SQL?
la variante suivante doit fonctionner sans evals multiples sur toutes les versions PostgreSQL supportées (8.4 ou plus récente):
WITH subq as (
SELECT array_agg(data) as agg,
dataid FROM datatable
-- WHERE clause ?
GROUP BY dataid)
SELECT foo(agg,dataid) FROM subq;