До сих пор наши запросы обращались только к одной таблице за раз. Запросы могут обращаться к нескольким таблицам одновременно или обращаться к одной и той же таблице таким образом, что несколько строк таблицы обрабатываются одновременно. Запросы, которые обращаются к нескольким таблицам (или нескольким экземплярам одной и той же таблицы) одновременно, называются запросами на соединение . Они объединяют строки из одной таблицы со строками из второй таблицы с выражением, указывающим, какие строки должны быть объединены в пары. Например, чтобы вернуть все записи о погоде вместе с местоположением соответствующего города, базе данных необходимо сравнить city
столбец каждой строки weather
таблицы со name
столбцом всех строк в cities
таблице и выбрать пары строк, в которых эти значения совпадение. [4]Это можно сделать с помощью следующего запроса:
SELECT * FROM weather JOIN cities ON 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)
Обратите внимание на две особенности результирующего набора:
- Для города Хейворд нет строки результатов. Это связано с тем, что в таблице нет соответствующей записи
cities
для Hayward, поэтому объединение игнорирует несопоставленные строки вweather
таблице. Вскоре мы увидим, как это можно исправить. - Есть две колонки, содержащие название города. Это правильно, потому что списки столбцов из таблиц и объединены
weather
.cities
Однако на практике это нежелательно, поэтому вы, вероятно, захотите указать выходные столбцы явно, а не использовать*
:
SELECT city, temp_lo, temp_hi, prcp, date, location
FROM weather JOIN cities ON city = name;
Поскольку у всех столбцов были разные имена, синтаксический анализатор автоматически нашел, к какой таблице они принадлежат. Если бы в двух таблицах были повторяющиеся имена столбцов, вам нужно было бы уточнить имена столбцов, чтобы показать, какой из них вы имели в виду, например:
SELECT weather.city, weather.temp_lo, weather.temp_hi,
weather.prcp, weather.date, cities.location
FROM weather JOIN cities ON weather.city = cities.name;
Считается хорошим стилем уточнять все имена столбцов в запросе на соединение, чтобы запрос не завершился ошибкой, если позже в одну из таблиц будет добавлено повторяющееся имя столбца.
Запросы соединения, которые мы видели до сих пор, также могут быть записаны в такой форме:
SELECT *
FROM weather, cities
WHERE city = name;
Этот синтаксис предшествует синтаксису JOIN
/ ON
, который был введен в SQL-92. Таблицы просто перечисляются в FROM
предложении, и в предложение добавляется выражение сравнения WHERE
. Результаты этого старого неявного синтаксиса и нового явного синтаксиса JOIN
/ ON
идентичны. Но для читателя запроса явный синтаксис облегчает понимание его значения: условие соединения вводится собственным ключевым словом, тогда как ранее условие было смешано с WHERE
предложением вместе с другими условиями.
Теперь мы выясним, как мы можем вернуть записи Хейворда. Мы хотим, чтобы запрос сканировал weather
таблицу и для каждой строки находил соответствующие cities
строки. Если подходящая строка не найдена, мы хотим, чтобы некоторые « пустые значения » были заменены на cities
столбцы таблицы. Такой запрос называется внешним соединением . (Соединения, которые мы видели до сих пор, являются внутренними соединениями .) Команда выглядит следующим образом:
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)
Этот запрос называется левым внешним соединением , потому что таблица, упомянутая слева от оператора соединения, будет иметь каждую из своих строк в выходных данных по крайней мере один раз, тогда как таблица справа будет содержать только те строки, которые соответствуют какой-либо строке оператора соединения. левый стол. При выводе строки левой таблицы, для которой нет совпадения с правой таблицей, столбцы правой таблицы заменяются пустыми (нулевыми) значениями.
Упражнение: Существуют также правые внешние соединения и полные внешние соединения. Попробуйте узнать, что они делают.
Мы также можем присоединиться к таблице против самой себя. Это называется самосоединением . В качестве примера предположим, что мы хотим найти все записи о погоде, которые находятся в температурном диапазоне других записей о погоде. Поэтому нам нужно сравнить столбцы temp_lo
и temp_hi
каждой weather
строки со столбцами temp_lo
и temp_hi
всех остальных weather
строк. Мы можем сделать это с помощью следующего запроса:
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 JOIN weather w2
ON 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)
Здесь мы переименовали таблицу погоды как w1
и w2
, чтобы иметь возможность различать левую и правую стороны соединения. Вы также можете использовать эти виды псевдонимов в других запросах, чтобы сэкономить время на наборе текста, например:
SELECT *
FROM weather w JOIN cities c ON w.city = c.name;
Вы столкнетесь с этим стилем сокращения довольно часто.
[4] Это только концептуальная модель. Соединение обычно выполняется более эффективно, чем реальное сравнение каждой возможной пары строк, но это незаметно для пользователя.
0 комментариев