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 se 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 comparar de verdade 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)
Devem ser observadas duas coisas no resultado produzido:
cidades
para Hayward, e a junção ignora as linhas da tabela clima sem correspondência. Veremos em breve como isto pode ser mudado.
clima
e cidades
estão concatenadas. Na prática isto não é desejado, sendo preferível, portanto, escrever a lista das colunas de saída explicitamente em vez de utilizar o *:
SELECT cidade, temp_min, temp_max, prcp, data, localizacao FROM clima, cidades WHERE cidade = nome;
Exercício: 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, mas é um bom estilo qualificar completamente os nomes das colunas nas consultas de junção:
SELECT clima.cidade, clima.temp_min, clima.temp_max, clima.prcp, clima.data, cidades.localizacao FROM clima, cidades WHERE cidades.nome = clima.cidade;
As consultas de junção do tipo visto até agora também poderiam 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 consultas vistas até agora são 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 (null) 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 registro de clima
com as colunas temp_min e temp_max de todos os outros registros da 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 permitir distinguir o lado esquerdo do 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á vista esta forma de abreviar com bastante freqüência.