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;