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

Usando junções para combinar dados de diferentes tabelas no PostgreSQL


Introdução


A divisão de dados relacionados em tabelas separadas pode ser benéfica do ponto de vista de consistência, flexibilidade e certos tipos de desempenho. No entanto, você ainda precisa de uma maneira razoável de reintegrar registros quando as informações relevantes abrangem várias tabelas.

Em bancos de dados relacionais, junções oferecem uma maneira de combinar os registros em duas ou mais tabelas com base em valores de campo comuns. Diferentes tipos de junções podem obter resultados diferentes dependendo de como as linhas sem correspondência devem ser tratadas. Neste guia, discutiremos os vários tipos de junções que o PostgreSQL oferece e como você pode usá-los para combinar dados de tabela de várias fontes.


O que são junções?


Resumindo, junções são uma maneira de exibir dados de várias tabelas. Eles fazem isso juntando registros de diferentes fontes com base em valores correspondentes em determinadas colunas. Cada linha resultante consiste em um registro da primeira tabela combinado com uma linha da segunda tabela, com base em uma ou mais colunas em cada tabela com o mesmo valor.

A sintaxe básica de uma junção é assim:
SELECT    *FROM    <first_table><join_type> <second_table>    <join_condition>;

Em uma junção, cada linha resultante é construída incluindo todas as colunas da primeira tabela seguidas por todas as colunas da segunda tabela. O SELECT parte da consulta pode ser usada para especificar as colunas exatas que você deseja exibir.

Várias linhas podem ser construídas a partir das tabelas originais se os valores nas colunas usadas para comparação não forem exclusivos. Por exemplo, imagine que você tem uma coluna sendo comparada da primeira tabela que possui dois registros com valor "vermelho". Combinada com isso, há uma coluna da segunda tabela que possui três linhas com esse valor. A junção produzirá seis linhas diferentes para esse valor representando as várias combinações que podem ser alcançadas.

O tipo de junção e as condições de junção determinam como cada linha exibida é construída. Isso afeta o que acontece com as linhas de cada tabela que não tem uma correspondência na condição de junção.

Por conveniência, muitas junções correspondem à chave primária em uma tabela com uma chave estrangeira associada na segunda tabela. Embora as chaves primárias e estrangeiras sejam usadas apenas pelo sistema de banco de dados para manter as garantias de consistência, seu relacionamento geralmente as torna boas candidatas para condições de junção.


Diferentes tipos de junções


Vários tipos de junções estão disponíveis, cada um dos quais potencialmente produzirá resultados diferentes. Entender como cada tipo é construído ajudará você a determinar qual é apropriado para diferentes cenários.

Junto interno


A junção padrão é chamada de junção interna . No PostgreSQL, isso pode ser especificado usando INNER JOIN ou simplesmente JOIN .

Aqui está um exemplo típico demonstrando a sintaxe de uma junção interna:
SELECT    *FROM    table_1[INNER] JOIN table_2    ON table_1.id = table_2.table_1_id;

Uma junção interna é o tipo mais restritivo de junção porque exibe apenas linhas criadas pela combinação de linhas de cada tabela. Quaisquer linhas nas tabelas constituintes que não tenham uma contraparte correspondente na outra tabela são removidas dos resultados. Por exemplo, se a primeira tabela tiver um valor "azul" na coluna de comparação e a segunda tabela não tiver nenhum registro com esse valor, essa linha será suprimida da saída.

Se você representar os resultados como um diagrama de Venn das tabelas de componentes, uma junção interna permitirá que você represente a área de sobreposição dos dois círculos. Nenhum dos valores que existiam apenas em uma das tabelas são exibidos.


Juntar à esquerda


Uma junção esquerda é uma junção que mostra todos os registros encontrados em uma junção interna, além de todos os não correspondentes linhas da primeira tabela. No PostgreSQL, isso pode ser especificado como um LEFT OUTER JOIN ou apenas como um LEFT JOIN .

A sintaxe básica de uma junção esquerda segue este padrão:
SELECT    *FROM    table_1LEFT JOIN table_2    ON table_1.id = table_2.table_1_id;

Uma junção esquerda é construída executando primeiro uma junção interna para construir linhas de todos os registros correspondentes em ambas as tabelas. Depois, os registros não correspondidos da primeira tabela também são incluídos. Como cada linha em uma junção inclui as colunas de ambas as tabelas, as colunas sem correspondência usam NULL como o valor para todas as colunas na segunda tabela.

Se você representar os resultados como um diagrama de Venn das tabelas de componentes, uma junção à esquerda permite representar todo o círculo esquerdo. As partes do círculo esquerdo representadas pela interseção entre os dois círculos terão dados adicionais complementados pela tabela direita.


Juntar à direita


Uma junção à direita é uma junção que mostra todos os registros encontrados em uma junção interna, além de todos os não correspondentes linhas da segunda tabela. No PostgreSQL, isso pode ser especificado como um RIGHT OUTER JOIN ou apenas como um RIGHT JOIN .

A sintaxe básica de uma junção direita segue este padrão:
SELECT    *FROM    table_1RIGHT JOIN table_2    ON table_1.id = table_2.table_1_id;

Uma junção à direita é construída executando primeiro uma junção interna para construir linhas de todos os registros correspondentes em ambas as tabelas. Em seguida, os registros não correspondentes da segunda tabela também são incluídos. Como cada linha em uma junção inclui as colunas de ambas as tabelas, as colunas sem correspondência usam NULL como o valor para todas as colunas na primeira tabela.

Se você representar os resultados como um diagrama de Venn das tabelas de componentes, uma junção à direita permite representar todo o círculo à direita. As partes do círculo direito representadas pela interseção entre os dois círculos terão dados adicionais complementados pela tabela da esquerda.


Participação completa


Uma junção completa é uma junção que mostra todos os registros encontrados em uma junção interna, além de todos os não correspondentes linhas de ambas as tabelas de componentes. No PostgreSQL, isso pode ser especificado como um FULL OUTER JOIN ou apenas como um FULL JOIN .

A sintaxe básica de uma junção completa segue este padrão:
SELECT    *FROM    table_1FULL JOIN table_2    ON table_1.id = table_2.table_1_id;

Uma junção completa é construída executando primeiro uma junção interna para construir linhas de todos os registros correspondentes em ambas as tabelas. Depois, os registros não correspondidos de ambas as tabelas também são incluídos. Como cada linha em uma junção inclui as colunas de ambas as tabelas, as colunas sem correspondência usam NULL como o valor de todas as colunas na outra tabela sem correspondência.

Se você representar os resultados como um diagrama de Venn das tabelas de componentes, uma junção completa permitirá que você represente inteiramente os dois círculos de componentes. A interseção dos dois círculos terá valores fornecidos por cada uma das tabelas componentes. As partes dos círculos fora da área de sobreposição terão os valores da tabela a que pertencem, usando NULL para preencher as colunas encontradas na outra tabela.


Juntar cruzado


Uma junção especial chamada CROSS JOIN também está disponível. Uma junção cruzada não usa nenhuma comparação para determinar se as linhas em cada tabela correspondem umas às outras. Em vez disso, os resultados são construídos simplesmente adicionando cada uma das linhas da primeira tabela a cada uma das linhas da segunda tabela.

Isso produz um produto cartesiano das linhas em duas ou mais tabelas. Na verdade, esse estilo de junção combina as linhas de cada tabela incondicionalmente. Portanto, se cada tabela tiver três linhas, a tabela resultante terá nove linhas contendo todas as colunas de ambas as tabelas.

Por exemplo, se você tiver uma tabela chamada t1 combinado com uma tabela chamada t2 , cada uma com linhas r1 , r2 e r3 , o resultado seria nove linhas combinadas assim:
t1.r1 + t2.r1t1.r1 + t2.r2t1.r1 + t2.r3t1.r2 + t2.r1t1.r2 + t2.r2t1.r2 + t2.r3t1.r3 + t2.r1t1.r3 + t2.r2t1.r3 + t2.r3


Auto-junção


Uma autojunção é qualquer junção que combina as linhas de uma tabela consigo mesma. Pode não ser imediatamente aparente como isso pode ser útil, mas na verdade tem muitas aplicações comuns.

Muitas vezes, as tabelas descrevem entidades que podem cumprir várias funções em relação umas às outras. Por exemplo, se você tiver uma tabela de people , cada linha pode conter uma mother coluna que faz referência a outras people na mesa. Uma autojunção permitiria unir essas diferentes linhas juntando uma segunda instância da tabela à primeira em que esses valores correspondam.

Como as autojunções fazem referência à mesma tabela duas vezes, os aliases de tabela são necessários para desambiguar as referências. No exemplo acima, por exemplo, você pode juntar as duas instâncias do people tabela usando os aliases people AS children e people AS mothers . Dessa forma, você pode especificar a qual instância da tabela você está se referindo ao definir as condições de junção.

Aqui está outro exemplo, desta vez representando relacionamentos entre funcionários e gerentes:
SELECT    *FROM    people AS employeeJOIN people AS manager    ON employee.manager_id = manager.id;



Condições de junção


Ao combinar tabelas, a condição de junção determina como as linhas serão combinadas para formar os resultados compostos. A premissa básica é definir as colunas em cada tabela que devem corresponder para que a junção ocorra nessa linha.

O ON cláusula


A maneira mais padrão de definir as condições para junções de tabelas é com o ON cláusula. O ON cláusula usa um sinal de igual para especificar as colunas exatas de cada tabela que serão comparadas para determinar quando uma junção pode ocorrer. O PostgreSQL usa as colunas fornecidas para unir as linhas de cada tabela.

O ON cláusula é a mais detalhada, mas também a mais flexível das condições de junção disponíveis. Ele permite especificidade independentemente de quão padronizados sejam os nomes das colunas de cada tabela que está sendo combinada.

A sintaxe básica do ON cláusula fica assim:
SELECT    *FROM    table1JOIN    table2ON    table1.id = table2.ident;

Aqui, as linhas de table1 e table2 será juntado sempre que o id coluna de table1 corresponde ao ident coluna de table2 . Como uma junção interna é usada, os resultados mostrarão apenas as linhas que foram unidas. Como a consulta usa o curinga * caractere, todas as colunas de ambas as tabelas serão exibidas.

Isso significa que tanto o id coluna de table1 e o ident coluna de table2 serão exibidos, mesmo que tenham o mesmo valor exato em virtude de satisfazer a condição de junção. Você pode evitar essa duplicação chamando as colunas exatas que deseja exibir no SELECT lista de colunas.


O USING cláusula


O USING cláusula é um atalho para especificar as condições de um ON cláusula que pode ser usada quando as colunas que estão sendo comparadas têm o mesmo nome em ambas as tabelas. O USING A cláusula recebe uma lista, entre parênteses, dos nomes das colunas compartilhadas que devem ser comparadas.

A sintaxe geral do USING cláusula usa este formato:
SELECT    *FROM    table1JOIN    table2USING    (id, state);

Esta junção combina table1 com table2 quando duas colunas que ambas as tabelas compartilham (id e state ) cada um tem valores correspondentes.

Esta mesma junção pode ser expressa mais detalhadamente usando ON assim:
SELECT    *FROM    table1JOIN    table2ON    table1.id = table2.id AND table1.state = table2.state;

Embora ambas as junções acima resultem na construção das mesmas linhas com os mesmos dados presentes, elas seriam exibidas ligeiramente diferentes. Enquanto o ON cláusula inclui todas as colunas de ambas as tabelas, a USING cláusula suprime as colunas duplicadas. Então, em vez de haver dois id separados colunas e dois state separados colunas (uma para cada tabela), os resultados teriam apenas uma de cada uma das colunas compartilhadas, seguidas por todas as outras colunas fornecidas por table1 e table2 .


O NATURAL cláusula


O NATURAL cláusula é mais uma abreviação que pode reduzir ainda mais a verbosidade do USING cláusula. Um NATURAL join não especifica qualquer colunas a serem correspondidas. Em vez disso, o PostgreSQL unirá automaticamente as tabelas com base em todas as colunas que possuem colunas correspondentes em cada banco de dados.

A sintaxe geral do NATURAL cláusula join fica assim:
SELECT    *FROM    table1NATURAL JOIN    table2;

Supondo que table1 e table2 ambos têm colunas chamadas id , state e company , a consulta acima seria equivalente a esta consulta usando o ON cláusula:
SELECT    *FROM    table1JOIN    table2ON    table1.id = table2.id AND table1.state = table2.state AND table1.company = table2.company;

E esta consulta usando o USING cláusula:
SELECT    *FROM    table1JOIN    table2USING    (id, state, company);

Como o USING cláusula, o NATURAL A cláusula suprime colunas duplicadas, portanto, haveria apenas uma única instância de cada uma das colunas unidas nos resultados.

Enquanto o NATURAL cláusula pode reduzir a verbosidade de suas consultas, deve-se ter cuidado ao usá-la. Como as colunas usadas para unir as tabelas são calculadas automaticamente, se as colunas nas tabelas de componentes forem alteradas, os resultados poderão ser muito diferentes devido a novas condições de união.



Condições de junção e WHERE cláusula


As condições de junção compartilham muitas características com as comparações usadas para filtrar linhas de dados usando WHERE cláusulas. Ambas as construções definem expressões que devem ser avaliadas como verdadeiras para que a linha seja considerada. Por causa disso, nem sempre é intuitivo qual é a diferença entre incluir comparações adicionais em um WHERE construir versus defini-los dentro da própria cláusula de junção.

Para entender as diferenças que resultarão, temos que dar uma olhada na ordem em que o PostgreSQL processa as diferentes partes de uma consulta. Nesse caso, os predicados na condição de junção são processados ​​primeiro para construir a tabela virtual unida na memória. Após este estágio, as expressões dentro do WHERE cláusula são avaliadas para filtrar as linhas resultantes.

Como exemplo, suponha que temos duas tabelas chamadas customer e order que precisamos nos unir. Queremos unir as duas tabelas combinando o customer.id coluna com o order.customer_id coluna. Além disso, estamos interessados ​​nas linhas na order tabela que tem um product_id de 12345.

Dados os requisitos acima, temos duas condições com as quais nos preocupamos. A maneira como expressamos essas condições, no entanto, determinará os resultados que recebemos.

Primeiro, vamos usar ambos como condições de junção para um LEFT JOIN :
SELECT    customer.id AS customer_id,    customer.name,    order.id AS order_id,    order.product_idFROM    customerLEFT JOIN    orderON    customer.id = order.customer_id AND order.product_id = 12345;

Os resultados poderiam ser algo assim:
 customer_id |   name   | order_id | product_id ------------+----------+----------+------------        4380 | Acme Co  |      480 |      12345        4380 | Acme Co  |      182 |      12345         320 | Other Co |      680 |      12345        4380 | Acme Co  |          |         320 | Other Co |          |          20 | Early Co |          |        8033 | Big Co   |          |(7 rows)

O PostgreSQL chegou a esse resultado executando as seguintes operações:
  1. Combine todas as linhas no customer tabela com o order tabela onde:
    • customer.id corresponde a order.customer_id .
    • order.product_id corresponde a 12345
  2. Como estamos usando uma junção à esquerda, inclua qualquer sem correspondência linhas da tabela esquerda (customer ), preenchendo as colunas da tabela direita (order ) com NULL valores.
  3. Exibe apenas as colunas listadas em SELECT especificação de coluna.

O resultado é que todas as nossas linhas unidas correspondem às duas condições que estamos procurando. No entanto, a junção à esquerda faz com que o PostgreSQL também inclua todas as linhas da primeira tabela que não satisfizeram a condição de junção. Isso resulta em linhas "sobradas" que parecem não seguir a intenção aparente da consulta.

Se movermos a segunda consulta (order.product_id =12345) para um WHERE cláusula, em vez de incluí-la como uma condição de junção, obtemos resultados diferentes:
SELECT    customer.id AS customer_id,    customer.name,    order.id AS order_id,    order.product_idFROM    customerLEFT JOIN    orderON    customer.id = order.customer_idWHERE    order.product_id = 12345;

Desta vez, apenas três linhas são exibidas:
 customer_id |   name   | order_id | product_id ------------+----------+----------+------------        4380 | Acme Co  |      480 |      12345        4380 | Acme Co  |      182 |      12345         320 | Other Co |      680 |      12345(3 rows)

A ordem em que as comparações são executadas é o motivo dessas diferenças. Desta vez, o PostgreSQL processa a consulta assim:
  1. Combine todas as linhas no customer tabela com o order tabela onde customer.id corresponde a order.customer_id .
  2. Como estamos usando uma junção à esquerda, inclua qualquer sem correspondência linhas da tabela esquerda (customer ), preenchendo as colunas da tabela direita (order ) com NULL valores.
  3. Avalie o WHERE cláusula para remover quaisquer linhas que não tenham 12345 como valor para o order.product_id coluna.
  4. Exibe apenas as colunas listadas em SELECT especificação de coluna.

Desta vez, embora estejamos usando uma junção à esquerda, o WHERE cláusula trunca os resultados filtrando todas as linhas sem o product_id correto . Como todas as linhas sem correspondência teriam product_id definido como NULL , isso remove todas as linhas sem correspondência que foram preenchidas pela junção esquerda. Ele também remove qualquer uma das linhas que foram correspondidas pela condição de junção que não passou nesta segunda rodada de verificações.

Compreender o processo básico que o PostgreSQL usa para executar suas consultas pode ajudá-lo a evitar alguns erros fáceis de cometer, mas difíceis de depurar, enquanto você trabalha com seus dados.


Conclusão


Neste guia, abordamos como as junções permitem que os bancos de dados relacionais combinem dados de diferentes tabelas para fornecer respostas mais valiosas. Falamos sobre as várias junções que o PostgreSQL suporta, a maneira como cada tipo monta seus resultados e o que esperar ao usar tipos específicos de junções. Depois, examinamos diferentes maneiras de definir as condições de junção e analisamos como a interação entre as junções e o WHERE cláusula pode levar a surpresas.

As junções são uma parte essencial do que torna os bancos de dados relacionais poderosos e flexíveis o suficiente para lidar com tantos tipos diferentes de consultas. Organizar dados usando limites lógicos e ainda ser capaz de recombinar os dados de novas maneiras caso a caso dá a bancos de dados relacionais como o PostgreSQL uma versatilidade incrível. Aprender como realizar essa junção entre tabelas permitirá que você crie consultas mais complexas e conte com o banco de dados para criar imagens completas de seus dados.