No Postgres 9.3 ou mais tarde, isso é melhor resolvido com um
LATERAL
Junte-se: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 a avaliação repetida da função (para cada coluna na saída - a função precisa ser chamada para cada linha de entrada de qualquer maneira).
LEFT JOIN LATERAL ... ON true
para evitar soltar linhas do lado esquerdo se a função não retornar nenhuma linha:- Qual é a diferença entre LATERAL e uma subconsulta no PostgreSQL?
Acompanhe seu comentário:
apenas as colunas expandidas produzidas pela chamada de função
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;
Mas como você não se importa com outras colunas, pode simplificar para:
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 é um
CROSS JOIN LATERAL
implícito . Se a função pode realmente retornar "sem linha" ocasionalmente, o resultado pode ser diferente:não obtemos valores NULL para as linhas, essas linhas são apenas eliminadas - e LIMIT
não os conta mais. Em versões mais antigas (ou geralmente) você também pode apenas decompor o tipo composto com a sintaxe correta:
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;
A desvantagem é que a função é avaliada uma vez para cada coluna na saída da função devido a uma fraqueza no planejador de consultas do Postgres. É melhor mover a chamada para uma subconsulta ou CTE e decompor o tipo de linha no
SELECT
externo . Como: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;
Mas você precisa nomear colunas individuais e não pode se safar com
SELECT *
a menos que você esteja de acordo com o tipo de linha no resultado de forma redundante. Relacionado:- Evite várias chamadas na mesma função ao expandir o resultado composto
- Como evitar várias avaliações de função com a sintaxe (func()).* em uma consulta SQL?