sql postgresql join plpgsql set-returning-functions

sql - Llama a una función set-return con un argumento de matriz varias veces



postgresql join (2)

Esta es una variación de la función plpgsql que devuelve varias columnas y se llama varias veces . Sin embargo, esperaba encontrar una solución a mi conjunto particular de circunstancias.

Tengo una función que procesa una matriz de filas con un parámetro dado y devuelve un conjunto de filas + una nueva columna.

CREATE OR REPLACE foo(data data[], parameter int) RETURNS SETOF enhanceddata AS ...

La función funciona en un caso de prueba con solo 1 conjunto de datos

SELECT * FROM foo( (SELECT ARRAY_AGG(data) FROM datatable GROUP BY dataid WHERE dataid = something), 1)

Pero me gustaría hacer que funcione con múltiples grupos de datos, sin pasar un dataid a la función. Intenté varias variaciones de:

SELECT dataid, (foo(ARRAY_AGG(data)),1).* FROM dataset WHERE dataid = something -- only testing on 1 GROUP BY dataid

Pero la función se llama una vez para cada columna.


En Postgres 9.3 o posterior, generalmente es mejor usar LEFT JOIN LATERAL ... ON true :

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 función foo() puede devolver filas , esa es la forma segura, ya que conserva todas las filas a la izquierda de la unión, incluso cuando no se devuelve ninguna fila a la derecha.

De lo contrario, o si desea excluir filas sin resultado de la unión lateral, use:

CROSS JOIN LATERAL foo(sub.arr)

o la taquigrafía:

, foo(sub.arr)

Hay una mención explícita en el manual.

La respuesta relacionada de Craig (referenciada por Daniel) se actualiza en consecuencia:


La función se llama varias veces en este contexto no por sus entradas, sino por cómo se implementa func().*

Esto se explica en: ¿Cómo evitar evaluaciones múltiples de funciones con la sintaxis (func ()). * En una consulta SQL?

La siguiente variante debería funcionar sin múltiples evaluaciones en todas las versiones compatibles de PostgreSQL (8.4 o posterior):

WITH subq as ( SELECT array_agg(data) as agg, dataid FROM datatable -- WHERE clause ? GROUP BY dataid) SELECT foo(agg,dataid) FROM subq;