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.

1
demandé sur Community 2014-09-30 00:03:25

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:

3
répondu Erwin Brandstetter 2017-05-23 12:24:22

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;
1
répondu Daniel Vérité 2017-05-23 11:45:22