En Postgres 9.3 o posterior, esto se resuelve mejor con un LATERAL
unirse:
SELECT *
FROM actors a
JOIN movies_actors ma on a.actor_id = ma.movie_id
LEFT JOIN LATERAL hi_lo(a.actor_id, length(a.name), ma.movie_id) x ON true
LIMIT 10;
Evita la evaluación repetida de la función (para cada columna en la salida; la función debe llamarse para cada fila de entrada de cualquier manera).LEFT JOIN LATERAL ... ON true
para evitar eliminar filas del lado izquierdo si la función no devuelve ninguna fila:
- ¿Cuál es la diferencia entre LATERAL y una subconsulta en PostgreSQL?
Seguimiento en su comentario:
solo las columnas expandidas producidas por la llamada de función
SELECT x.* -- that's all!
FROM actors a
JOIN movies_actors ma on a.actor_id = ma.movie_id
LEFT JOIN LATERAL hi_lo(a.actor_id, length(a.name), ma.movie_id) x ON true
LIMIT 10;
Pero como no le importan otras columnas, puede simplificar a:
SELECT x.*
FROM actors a
JOIN movies_actors ma on a.actor_id = ma.movie_id
, hi_lo(a.actor_id, length(a.name), ma.movie_id) x
LIMIT 10;
Que es un CROSS JOIN LATERAL
implícito . Si la función puede devolver "ninguna fila" ocasionalmente, el resultado puede ser diferente:no obtenemos valores NULL para las filas, esas filas simplemente se eliminan y LIMIT
ya no los cuenta.
En versiones anteriores (o en general) también puede simplemente descomponer el tipo compuesto con la sintaxis correcta:
SELECT *, (hi_lo(a.actor_id, length(a.name), ma.movie_id)).* -- note extra parentheses!
FROM actors a
JOIN movies_actors ma on a.actor_id = ma.movie_id
LIMIT 10;
El inconveniente es que la función se evalúa una vez para cada columna en el resultado de la función debido a una debilidad en el planificador de consultas de Postgres. Es mejor mover la llamada a una subconsulta o CTE y descomponer el tipo de fila en el SELECT
externo. . Me gusta:
SELECT actor_id, movie_id, (x).* -- explicit column names for the rest
FROM (
SELECT *, hi_lo(a.actor_id, length(a.name), ma.movie_id) AS x
FROM actors a
JOIN movies_actors ma on a.actor_id = ma.movie_id
LIMIT 10
) sub;
Pero debe nombrar columnas individuales y no puede salirse con la suya con SELECT *
a menos que esté de acuerdo con el tipo de fila en el resultado de forma redundante. Relacionado:
- Evite varias llamadas a la misma función al expandir el resultado compuesto
- ¿Cómo evitar múltiples evaluaciones de funciones con la sintaxis (func()).* en una consulta SQL?