2.6. Junções entre tabelas

PostgreSQL 14.5: Junções entre tabelas

Até agora as consultas somente acessaram uma tabela de cada vez. As consultas podem acessar várias tabelas de uma vez, ou acessar a mesma tabela de uma maneira que várias linhas da tabela sejam processadas ao mesmo tempo. A consulta que acessa várias linhas da mesma tabela, ou de tabelas diferentes, de uma vez, é chamada de consulta de junção. Como exemplo, suponha que se queira listar todas as linhas de clima junto com a localização da cidade associada. Para fazer isto, é necessário comparar a coluna cidade de cada linha da tabela clima com a coluna nome de todas as linhas da tabela cidades, e selecionar os pares de linha onde estes valores são correspondentes.

Nota: Este é apenas um modelo conceitual, a junção geralmente é realizada de uma maneira mais eficiente que realmente comparar cada par de linhas possível, mas isto não é visível para o usuário.

Esta operação pode ser efetuada por meio da seguinte consulta:

SELECT *
    FROM clima, cidades
    WHERE cidade = nome;

     cidade      | temp_min | temp_max | prcp |    data    |     nome      | localizacao
-----------------+----------+----------+------+------------+---------------+-------------
 São Francisco   |       46 |       50 | 0.25 | 1994-11-27 | São Francisco | (-194,53)
 São Francisco   |       43 |       57 |    0 | 1994-11-29 | São Francisco | (-194,53)
(2 linhas)

Duas coisas devem ser observadas no conjunto de resultados produzido:

Exercício: Tentar descobrir a semântica desta consulta quando a cláusula WHERE é omitida.

Como todas as colunas possuem nomes diferentes, o analisador encontra automaticamente a tabela que a coluna pertence. Se existissem nomes de colunas duplicados nas duas tabelas, seria necessário qualificar os nomes das colunas para mostrar qual delas está sendo referenciada, como em:

SELECT clima.cidade, clima.temp_min, clima.temp_max,
       clima.prcp, clima.data, cidades.localizacao
    FROM clima, cidades
    WHERE cidades.nome = clima.cidade;

Muitos consideram um bom estilo qualificar todos os nomes de colunas nas consultas de junção, para que a consulta não falhe ao se adicionar posteriormente um nome de coluna duplicado a uma das tabelas.

As consultas de junção do tipo visto até agora também podem ser escritas da seguinte forma alternativa:

SELECT *
    FROM clima INNER JOIN cidades ON (clima.cidade = cidades.nome);

A utilização desta sintaxe não é tão comum quanto a usada acima, mas é mostrada para ajudar a entender os próximos tópicos.

Agora vamos descobrir como se faz para obter as linhas de Hayward. Desejamos o seguinte: que a consulta varra a tabela clima e, para cada uma de suas linhas, encontre a linha correspondente na tabela cidades. Se não for encontrada nenhuma linha correspondente, desejamos que sejam colocados "valores vazios" nas colunas da tabela cidades. Este tipo de consulta é chamada de junção externa (outer join). As junções vistas até agora foram junções internas (inner join). O comando então fica assim:

SELECT *
    FROM clima LEFT OUTER JOIN cidades ON (clima.cidade = cidades.nome);

     cidade      | temp_min | temp_max | prcp |    data    |     nome      | localizacao
-----------------+----------+----------+------+------------+---------------+------------
 Hayward         |       37 |       54 |      | 1994-11-29 |               |
 São Francisco   |       46 |       50 | 0.25 | 1994-11-27 | São Francisco | (-194,53)
 São Francisco   |       43 |       57 |    0 | 1994-11-29 | São Francisco | (-194,53)
(3 linhas)

Esta consulta é chamada de junção externa esquerda (left outer join), porque a tabela mencionada à esquerda do operador de junção terá cada uma de suas linhas aparecendo na saída pelo menos uma vez, enquanto a tabela à direita terá somente as linhas correspondendo a alguma linha da tabela à esquerda aparecendo na saída. Ao listar uma linha da tabela à esquerda, para a qual não existe nenhuma linha correspondente na tabela à direita, são colocados valores vazios (nulos) nas colunas da tabela à direita.

Exercício: Existem também a junção externa direita (right outer join) e a junção externa completa (full outer join). Tente descobrir o que fazem.

Também é possível fazer a junção da tabela consigo mesma. Isto é chamado de autojunção (self join). Como exemplo, suponha que desejamos descobrir todas as linhas de clima que estão no intervalo de temperatura de outros registros de clima. Para isso é necessário comparar as colunas temp_min e temp_max de cada linha da tabela clima com as colunas temp_min e temp_max de todos as outras linhas da mesma tabela clima, o que pode ser feito utilizando a seguinte consulta:

SELECT C1.cidade, C1.temp_min AS menor, C1.temp_max AS maior,
    C2.cidade, C2.temp_min AS menor, C2.temp_max AS maior
    FROM clima C1, clima C2
    WHERE C1.temp_min < C2.temp_min
    AND C1.temp_max > C2.temp_max;

     cidade      | menor | maior |     cidade    | menor | maior
-----------------+-------+-------+---------------+-------+-------
 São Francisco   |    43 |    57 | São Francisco |    46 |    50
 Hayward         |    37 |    54 | São Francisco |    46 |    50
(2 linhas)

A tabela clima teve seu nome mudado para C1 e C2, para ser possível distinguir o lado esquerdo e o lado direito da junção. Estes tipos de "aliases" também podem ser utilizados em outras consultas para reduzir a digitação como, por exemplo:

SELECT *
    FROM clima w, cidades c
    WHERE w.cidade = c.nome;

Será encontrada esta forma de abreviar com bastante freqüência.

SourceForge.net Logo CSS válido!