До сих пор наши запросы обращались только к одной таблице за раз. Запросы могут обращаться к нескольким таблицам одновременно или обращаться к одной и той же таблице таким образом, что несколько строк таблицы обрабатываются одновременно. Запросы, которые обращаются к нескольким таблицам (или нескольким экземплярам одной и той же таблицы) одновременно, называются запросами на соединение . Они объединяют строки из одной таблицы со строками из второй таблицы с выражением, указывающим, какие строки должны быть объединены в пары. Например, чтобы вернуть все записи о погоде вместе с местоположением соответствующего города, базе данных необходимо сравнить 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таблице. Вскоре мы увидим, как это можно исправить.
  • Есть две колонки, содержащие название города. Это правильно, потому что списки столбцов из таблиц и объединены weathercitiesОднако на практике это нежелательно, поэтому вы, вероятно, захотите указать выходные столбцы явно, а не использовать *
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;

Этот синтаксис предшествует синтаксису JOINON, который был введен в SQL-92. Таблицы просто перечисляются в FROMпредложении, и в предложение добавляется выражение сравнения WHERE. Результаты этого старого неявного синтаксиса и нового явного синтаксиса JOINONидентичны. Но для читателя запроса явный синтаксис облегчает понимание его значения: условие соединения вводится собственным ключевым словом, тогда как ранее условие было смешано с 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] Это только концептуальная модель. Соединение обычно выполняется более эффективно, чем реальное сравнение каждой возможной пары строк, но это незаметно для пользователя.