Até agora, as nossas consultas só acederam a uma tabela de cada vez. As consultas podem aceder a várias tabelas ao mesmo tempo, ou aceder à mesma tabela de tal forma que várias linhas da tabela estão a ser processadas ao mesmo tempo. Uma consulta que acede a várias linhas da mesma tabela ou de tabelas diferentes ao mesmo tempo é chamada de consulta de junção. Como exemplo, digamos que se deseja listar todos os registos meteorológicos juntamente com a localização da cidade associada. Para tal, precisamos de comparar a coluna da cidade de cada linha da tabela meteorológica com a coluna do nome de todas as linhas da tabela de cidades, e seleccionar os pares de linhas onde estes valores correspondem.
Nota: Este é apenas um modelo conceptual. A junção é normalmente realizada de uma forma mais eficiente do que comparar realmente cada par de linhas possível, mas isto é invisível para o utilizador.
Isto seria realizado através da seguinte consulta:
SELECT * FROM weather, cities WHERE city = name;
city | temp_lo | temp_hi | prcp | date | name | location---------------+---------+---------+------+------------+---------------+----------- San Francisco | 46 | 50 | 0.25 | 1994-11-27 | San Francisco | (-194,53) San Francisco | 43 | 57 | 0 | 1994-11-29 | San Francisco | (-194,53)(2 rows)
Observe duas coisas sobre o conjunto de resultados:
-
Não há linha de resultados para a cidade de Hayward. Isto porque não existe uma entrada correspondente na tabela
cities
para Hayward, por isso a junção ignora as linhas inigualáveis na tabela meteorológica. Veremos em breve como isto pode ser corrigido. -
Há duas colunas contendo o nome da cidade. Isto é correcto porque as listas de colunas da tabela
weather
e a tabelacities
são concatenadas. Na prática, porém, isto é indesejável, pelo que provavelmente irá querer listar as colunas de saída explicitamente em vez de usar *:SELECT city, temp_lo, temp_hi, prcp, date, location FROM weather, cities WHERE city = name;
Exercício: Tentativa de descobrir a semântica desta consulta quando a cláusula WHERE for omitida.
Desde que todas as colunas tinham nomes diferentes, o analisador descobriu automaticamente a que tabela pertencem, mas é um bom estilo para qualificar completamente os nomes das colunas nas consultas de junção:
SELECT weather.city, weather.temp_lo, weather.temp_hi, weather.prcp, weather.date, cities.location FROM weather, cities WHERE cities.name = weather.city;
P>P>Perguntas do tipo visto até agora também podem ser escritas nesta forma alternativa:
SELECT * FROM weather INNER JOIN cities ON (weather.city = cities.name);
Esta sintaxe não é tão vulgarmente utilizada como a acima referida, mas mostramos aqui para o ajudar a compreender os seguintes tópicos.
Agora vamos descobrir como podemos voltar a ter os registos Hayward. O que queremos que a consulta faça é digitalizar a tabela weather
e para cada linha encontrar a correspondência cities
linha. Se não for encontrada uma linha correspondente, queremos que alguns “valores vazios” sejam substituídos por cities
colunas da tabela. Este tipo de consulta é chamado de união externa. (As junções que vimos até agora são junções internas.) O comando parece assim:
SELECT * FROM weather LEFT OUTER JOIN cities ON (weather.city = cities.name); city | temp_lo | temp_hi | prcp | date | name | location---------------+---------+---------+------+------------+---------------+----------- Hayward | 37 | 54 | | 1994-11-29 | | San Francisco | 46 | 50 | 0.25 | 1994-11-27 | San Francisco | (-194,53) San Francisco | 43 | 57 | 0 | 1994-11-29 | San Francisco | (-194,53)(3 rows)
Esta consulta chama-se junção externa esquerda porque a tabela mencionada à esquerda do operador de junção terá cada uma das suas linhas na saída pelo menos uma vez, enquanto a tabela à direita terá apenas a saída das linhas que correspondem a alguma linha da tabela da esquerda. Quando se produz uma linha da tabela da esquerda para a qual não há correspondência da tabela da direita, os valores vazios (nulos) são substituídos pelas colunas da tabela da direita.
Exercicio: Há também juntas exteriores direitas e juntas exteriores completas. Tente descobrir o que fazem.
Também podemos juntar uma tabela contra si próprios. A isto chama-se uma auto-entrada. Como exemplo, suponha que desejamos encontrar todos os registos meteorológicos que se encontram na gama de temperaturas de outros registos meteorológicos. Portanto, precisamos de comparar as colunas temp_lo e temp_hi de cada weather
linha com as colunas temp_lo e temp_hi de todas as outras weather
linhas. Podemos fazê-lo com a seguinte pergunta:
SELECT W1.city, W1.temp_lo AS low, W1.temp_hi AS high, W2.city, W2.temp_lo AS low, W2.temp_hi AS high FROM weather W1, weather W2 WHERE W1.temp_lo < W2.temp_lo AND W1.temp_hi > W2.temp_hi; city | low | high | city | low | high---------------+-----+------+---------------+-----+------ San Francisco | 43 | 57 | San Francisco | 46 | 50 Hayward | 37 | 54 | San Francisco | 46 | 50(2 rows)
P>Aqui temos novamente rotulado a tabela meteorológica como W1 e W2 para podermos distinguir o lado esquerdo e direito da junção. Também pode usar este tipo de pseudónimos noutras consultas para salvar alguma datilografia, por exemplo:
SELECT * FROM weather w, cities c WHERE w.city = c.name;
Encontrará este estilo de abreviação com bastante frequência.