Uso de junções laterais¶
Em uma cláusula FROM, o constructo LATERAL permite que uma exibição em linha faça referência a colunas de expressões de tabela anteriores.
Por exemplo, se a exibição em linha for uma subconsulta, a subconsulta poderá processar as linhas da tabela à esquerda da subconsulta. Por exemplo:
Esse comportamento é um pouco semelhante a uma subconsulta correlacionada. A subconsulta após a palavra-chave LATERAL é semelhante à própria subconsulta correlacionada, e a left_hand_table_expression é semelhante à consulta externa. Uma junção lateral, diferentemente de uma subconsulta correlacionada, pode retornar várias linhas, cada uma das quais pode ter várias colunas.
Outros tipos de junções não passam diretamente as linhas da expressão da tabela da esquerda para a expressão da tabela da direita para processamento.
Um uso comum de uma junção lateral é combiná-la com uma chamada à função de tabela FLATTEN para processar uma estrutura de dados complexa, como um tipo de dados ARRAY ou VARIANT, e extrair os valores. Para obter um exemplo, consulte LATERAL.
Diferentemente da saída de outros tipos de junções, a saída de uma junção lateral inclui apenas as linhas geradas a partir da exibição em linha (a subconsulta); depois que as linhas da subconsulta são geradas, elas não são unidas de forma cruzada a todas as linhas da tabela no lado esquerdo.
Terminologia¶
Considere o seguinte fragmento de código:
O lado esquerdo da junção lateral é uma expressão de tabela (te1). O lado direito da junção lateral é uma exibição em linha (iv1).
Expressão de tabela: neste tópico, a expressão de tabela no lado esquerdo de uma junção lateral, como a expressão de tabela acima denominada
te1, pode ser praticamente qualquer expressão válida que seja avaliada como uma tabela. Por exemplo:Uma tabela.
Uma exibição.
Uma subconsulta.
A saída de uma função de tabela.
O resultado de uma junção anterior (uma junção lateral ou outro tipo de junção).
Exibição em linha: neste tópico, a expressão no lado direito de uma junção lateral (neste caso,
iv1) é chamada de “exibição em linha”. Nesse contexto, uma exibição em linha válida pode ser uma das seguintes:Uma exibição definida dentro da instrução e válida somente durante a duração da instrução.
Uma subconsulta.
Uma função de tabela: ou uma função de tabela interna como FLATTEN ou uma função de tabela definida pelo usuário (UDTF).
A exibição em linha não pode ser uma tabela.
Junção cruzada: neste tópico, o termo “junção cruzada” não se refere apenas a junções cruzadas explícitas, mas também a junções internas e externas, incluindo todas as variações (junções naturais, junções externas à esquerda/direita/completas etc.).
Uma atualização sobre junções¶
Uma junção é um processo de duas etapas. Primeiro, o servidor emparelha duas linhas, que geralmente estão em tabelas diferentes e que quase sempre estão relacionadas de alguma forma. Em segundo lugar, o servidor une as colunas de cada linha do par em uma única linha.
Muitas das consultas de exemplo usam os dados mostrados abaixo:
Aqui está uma junção interna simples (não é uma junção lateral):
Como você pode ver, as linhas são emparelhadas com base nos IDs de departamento correspondente.
A junção pega as colunas de duas linhas de entrada correspondentes (“emparelhadas”) e gera uma linha de saída que contém todas as colunas de ambas as linhas de entrada. (É claro que, ao modificar a lista SELECT, você pode alterar as colunas; no entanto, no caso mais simples, todas as colunas de entrada são incluídas na saída)
Uma junção lateral emparelha as linhas de forma diferente. Entretanto, a segunda metade do processo, a “junção” de linhas emparelhadas, é semelhante: a linha de saída conterá (quase sempre) uma ou mais colunas de cada membro do par de linhas de entrada.
Como uma junção lateral emparelha linhas¶
Uma junção lateral se comporta de forma diferente de outros tipos de junção. Uma junção lateral se comporta como se o servidor executasse um loop semelhante ao seguinte:
Esta seção se concentra na parte de “emparelhamento” do processo, que é diferente para junções laterais.
A construção LATERAL permite que uma exibição em linha no lado direito da junção lateral faça referência a colunas de uma expressão de tabela que esteja fora da exibição. (No exemplo abaixo, a “exibição em linha” é, na verdade, uma subconsulta)
Neste exemplo, a cláusula WHERE na subconsulta à direita refere-se a um valor da tabela à esquerda.
As diferenças entre uma junção lateral e uma junção cruzada são muito maiores do que o simples acesso às colunas. Os próximos parágrafos contrastam esses dois tipos de junções, começando com a junção cruzada tradicional.
Uma junção cruzada combina cada linha da tabela à esquerda com cada linha da tabela à direita. O resultado é um produto cartesiano.
Conceitualmente, uma junção cruzada é semelhante a um loop aninhado, como no pseudocódigo abaixo:
Se a tabela à esquerda tiver n linhas e a tabela à direita tiver m* linhas, o resultado da junção cruzada terá n × m linhas. Por exemplo, se a tabela à esquerda tiver 1.000 linhas e a tabela à direita tiver 100 linhas, o resultado da junção interna será 100.000 linhas. Isso é exatamente o que se espera de loops aninhados; se o loop externo for executado 1.000 vezes e o loop interno for executado 100 vezes por iteração do loop externo, a instrução mais interna será executada 100.000 vezes. (É claro que os programadores de SQL raramente escrevem junções cruzadas puras sem nenhuma condição de junção na cláusula FROM ou na cláusula WHERE)
Uma junção lateral emparelha os registros de forma muito diferente. Aqui está o pseudocódigo para a implementação de uma junção lateral:
A junção lateral tem apenas um loop, não dois loops aninhados, o que altera a saída.
Para a junção cruzada, a saída foi de 100.000 linhas. Para uma junção lateral com a mesma tabela de 1.000 linhas no lado esquerdo e usando uma exibição em linha do lado direito (como uma subconsulta) que emite uma linha de saída por linha de entrada, a saída da junção lateral será de 1.000 linhas, não de 100.000 linhas.
Você pode pensar em uma junção lateral da seguinte forma: para cada linha de entrada da tabela da esquerda, a exibição em linha da direita produz 0 ou mais linhas. Cada uma dessas linhas de saída da subconsulta é então unida à linha de entrada (e não à tabela inteira no lado esquerdo) para produzir uma linha que contenha as colunas selecionadas da subconsulta e as colunas da linha de entrada LHT.
A exibição em linha no lado direito de uma junção lateral não produz necessariamente uma linha de saída exata para cada linha de entrada. Para qualquer linha de entrada, a saída do lado direito pode ser 0 linha, 1 linha ou várias linhas. Cada uma dessas linhas de saída será unida às colunas da linha de entrada original.
Se a subconsulta não produzir exatamente uma linha de saída para cada linha de entrada, a junção lateral não necessariamente produzirá exatamente o mesmo número de linhas que há na tabela da esquerda. Se a tabela à esquerda tiver 1.000 linhas e a exibição em linha produzir 2 linhas de saída para cada linha de entrada, o resultado da junção lateral será 2.000 linhas.
Em cada um dos exemplos de junção lateral até agora, não havia nenhuma cláusula ON ou WHERE na consulta externa para emparelhar os registros. O emparelhamento (se houver) é feito pela exibição em linha com base na linha individual passada para a exibição em linha. Isso fica razoavelmente claro quando a exibição em linha é uma subconsulta com uma cláusula WHERE. Isso não é necessariamente tão óbvio em outros casos, como quando a expressão do lado direito é uma função de tabela em vez de uma subconsulta. (Um exemplo posterior mostra uma expressão à direita que usa a função de tabela FLATTEN em vez de uma subconsulta)
Os leitores que são fluentes em subconsultas correlacionadas ou em junções de funções de tabela podem achar as seguintes comparações úteis para entender como as junções laterais diferem das junções cruzadas. Os leitores que não estiverem familiarizados com subconsultas correlacionadas ou funções de tabela de junção podem ignorar essas seções.
Semelhanças entre as funções de tabela com junção e as junções laterais¶
Uma junção lateral é semelhante a uma “junção” entre uma tabela e uma função de tabela definida pelo usuário (UDTF). Por exemplo, considere a seguinte instrução SQL:
O pseudocódigo para implementar a junção entre a tabela e a UDTF é o seguinte:
Isso é essencialmente idêntico ao código para implementar uma junção lateral:
Exemplo: uso de uma junção lateral com a função de tabela FLATTEN¶
As junções laterais são usadas com frequência com a função de tabela FLATTEN integrada. A função FLATTEN é frequentemente usada com tipos de dados que podem armazenar vários valores (como ARRAY, VARIANT e OBJECT). Por exemplo, uma matriz normalmente contém vários valores. Da mesma forma, uma coluna VARIANT pode conter um valor de dados JSON, que pode conter um dicionário (hash) ou uma lista. (E isso, por sua vez, pode conter outros valores)
Você pode criar valores ARRAY da seguinte forma:
A função FLATTEN pode extrair valores de dentro desses valores. A função usa uma única expressão do tipo VARIANT, OBJECT ou ARRAY, e extrai os valores dessa expressão em um conjunto de linhas (0 ou mais linhas, cada uma contendo 1 ou mais colunas). Esse conjunto de linhas é equivalente a uma exibição ou a uma tabela. Essa exibição existe apenas durante o período da instrução em que é definida, por isso é comumente chamada de “exibição em linha”.
O exemplo a seguir usa FLATTEN para extrair valores de uma matriz (sem usar uma junção lateral):
A exibição em linha gerada por FLATTEN pode ser (mas não precisa) usada com a palavra-chave LATERAL. Por exemplo:
Quando usada com a palavra-chave LATERAL, a exibição em linha pode conter uma referência a colunas em uma tabela que a precede: