PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Qual é a diferença entre LATERAL JOIN e uma subconsulta no PostgreSQL?

O que é a LATERAL participar?


O recurso foi introduzido com o PostgreSQL 9.3. O manual:

Subconsultas que aparecem em FROM pode ser precedido pela palavra chaveLATERAL . Isso permite que eles façam referência às colunas fornecidas pelo FROM anterior Itens. (Sem LATERAL , cada subconsulta é avaliada independentemente e, portanto, não pode fazer referência cruzada a nenhum outro FROM item.)

Funções de tabela que aparecem em FROM também pode ser precedido pela palavra-chave LATERAL , mas para funções a palavra-chave é opcional; os argumentos da função podem conter referências a colunas fornecidas por FROM precedente itens em qualquer caso.

Exemplos de código básicos são fornecidos lá.

Mais como um correlacionado subconsulta


Um LATERAL join é mais como uma subconsulta correlacionada, não uma subconsulta simples, naquelas expressões à direita de um LATERAL join são avaliados uma vez para cada linha à esquerda - assim como um correlacionado subconsulta - enquanto uma subconsulta simples (expressão de tabela) é avaliada uma vez só. (O planejador de consultas tem maneiras de otimizar o desempenho para ambos.)
Resposta relacionada com exemplos de código para ambos lado a lado, resolvendo o mesmo problema:
  • Otimize a consulta GROUP BY para recuperar a última linha por usuário

Para retornar mais de uma coluna , um LATERAL join é normalmente mais simples, limpo e rápido.
Além disso, lembre-se de que o equivalente a uma subconsulta correlacionada é LEFT JOIN LATERAL ... ON true :
  • Chame uma função de retorno de conjunto com um argumento de matriz várias vezes

Coisas que uma subconsulta não pode fazer


Existem coisas que um LATERAL join pode fazer, mas uma subconsulta (correlacionada) não pode (facilmente). Uma subconsulta correlacionada pode retornar apenas um único valor, não várias colunas e nem várias linhas - com exceção de chamadas de função simples (que multiplicam as linhas de resultado se retornarem várias linhas). Mas mesmo certas funções de retorno de conjunto só são permitidas no FROM cláusula. Como unnest() com vários parâmetros no Postgres 9.4 ou posterior. O manual:

Isso só é permitido no FROM cláusula;

Portanto, isso funciona, mas não pode (facilmente) ser substituído por uma subconsulta:
CREATE TABLE tbl (a1 int[], a2 int[]);
SELECT * FROM tbl, unnest(a1, a2) u(elem1, elem2);  -- implicit LATERAL

A vírgula (, ) no FROM cláusula é uma notação curta para CROSS JOIN .
LATERAL é assumido automaticamente para funções de tabela.
Sobre o caso especial de UNNEST( array_expression [, ... ] ) :
  • Como você declara uma função set-returning para ser permitida apenas na cláusula FROM?

Funções de retorno de set no SELECT lista


Você também pode usar funções de retorno de conjunto como unnest() no SELECT lista diretamente. Isso costumava exibir um comportamento surpreendente com mais de uma dessas funções no mesmo SELECT list até o Postgres 9.6. Mas finalmente foi higienizado com o Postgres 10 e é uma alternativa válida agora (mesmo que não seja SQL padrão). Ver:
  • Qual ​​é o comportamento esperado para várias funções de retorno de conjunto na cláusula SELECT?

Com base no exemplo acima:
SELECT *, unnest(a1) AS elem1, unnest(a2) AS elem2
FROM   tbl;

Comparação:

dbfiddle para página 9.6 aqui
dbfiddle para página 10 aqui

Esclareça a desinformação


O manual:

Para o INNER e OUTER tipos de junção, uma condição de junção deve ser especificada, ou seja, exatamente um de NATURAL , ON join_condition ,ou USING (join_column [, ...]). Veja abaixo o significado.
Para CROSS JOIN , nenhuma dessas cláusulas pode aparecer.

Portanto, essas duas consultas são válidas (mesmo que não sejam particularmente úteis):
SELECT *
FROM   tbl t
LEFT   JOIN LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t ON TRUE;

SELECT *
FROM   tbl t, LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t;

Enquanto este não é:

SELECT *
FROM   tbl t
LEFT   JOIN LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t;


É por isso que o exemplo de código de Andomar está correto (o CROSS JOIN não requer uma condição de junção) e Attila é não foi.