Left join (SQL) — пример, подробное описание, ошибки использования
В любой реальной реляционной базе данных вся информация распределяется по отдельным таблицам. Многие из таблиц имеют зафиксированные в схеме установленные связи друг с другом. Однако с помощью запросов Sql вполне реально проложить связь между данными, не заложенную в схеме. Это осуществляется путем выполнения операции соединения join, которая позволяет выстроить отношения между любым количеством таблиц и соединить даже, казалось бы, разрозненные данные.
В данной статье пойдет речь конкретно о левом внешнем соединении. Прежде чем приступить к описанию данного типа соединения, добавим в базу данных некоторые таблицы.
Подготовка необходимых таблиц
Допустим, в нашей базе данных имеется информация о людях и их недвижимом имуществе. Основная информация основывается на трех таблицах: Peoples (люди), Realty (недвижимость), Realty_peoples (таблица с отношениями, кому из людей какая недвижимость принадлежит). Предположим, в таблицах хранятся следующие данные по людям:
Peoples | ||||
id | L_name | F_name | Middle_name | Birthday |
1 | Иванова | Дарья | Борисовна | 16.07.2000 |
2 | Пугин | Владислав | Николаевич | 29.01.1986 |
3 | Евгеньин | Александр | Федерович | 30.04.1964 |
4 | Аннина | Любовь | Павловна | 31. 12.1989 |
5 | Герасимовская | Надежда | Павловна | 14.03.1992 |
6 | Герасимовский | Олег | Альбертович | 29.01.1985 |
7 | Сухановский | Юрий | Андреевич | 25.09.1976 |
8 | Сухановская | Юлия | Юрьевна | 01.10.2001 |
По недвижимости:
Realty | |
id | address |
1 | г. Архангельск, ул. Воронина, д. 7, кв.6 |
2 | г. Архангельск, ул. Северодвинская, д. 84, кв. 9, комн. 5 |
3 | Архангельская область, г. Северодвинск, ул. Ленина, д. 134, кв. 85 |
4 | Архангельская область, г. Новодвинск, ул. Пролетарская, д. 16, кв. 137 |
5 | г. Архангельск, пл. Терехина, д. 89, кв. 13 |
По отношениям люди — недвижимость:
Realty_peoples | ||
id_peoples | id_realty | type |
7 | 3 | Общая совместная собственность |
8 | 3 | Общая совместная собственность |
3 | 5 | Собственность |
7 | 1 | Собственность |
5 | 4 | Общая долевая собственность |
6 | 4 | Общая долевая собственность |
Left join (Sql) – описание
Левое соединение имеет следующий синтаксис:
Table_A LEFT JOIN table_B [{ON предикат} | {USING список_столбцов}] |
И схематично выглядит так:
И переводится данное выражение как «Выбрать все без исключения строки из таблицы А, а из таблицы В вывести только совпадающие по предикату строки. Если в таблице В не нашлось пары для строк таблицы А, то заполнить результирующие столбцы Null — значениями».
Чаще всего при выполнении левого соединения указывается ON, USING используют, лишь когда названия столбцов, по которым планируется выполнить соединение, совпадают.
Left join — примеры использования
С помощью левого соединения мы можем посмотреть, у всех ли людей из списка Peoples имеется недвижимость. Для этого выполним следующий в left join sql пример запроса:
SELECT Peoples.*, Realty_peoples.id_realty, Realty_peoples.type FROM Peoples LEFT JOIN Realty_peoples ON Peoples.id = Realty_peoples.id_peoples; |
И получим следующий результат:
Запрос1 | ||||||
id | L_name | F_name | Middle_name | Birthday | id_realty | type |
1 | Иванова | Дарья | Борисовна | 16. 07.2000 | ||
2 | Пугин | Владислав | Николаевич | 29.01.1986 | ||
3 | Евгеньин | Александр | Федерович | 30.04.1964 | 5 | Собственность |
4 | Аннина | Любовь | Павловна | 31.12.1989 | ||
5 | Герасимовская | Надежда | Павловна | 14.03.1992 | 4 | Общая долевая собственность |
6 | Герасимовский | Олег | Альбертович | 29. 01.1985 | 4 | Общая долевая собственность |
7 | Сухановский | Юрий | Андреевич | 25.09.1976 | 1 | Собственность |
7 | Сухановский | Юрий | Андреевич | 25.09.1976 | 3 | Общая совместная собственность |
8 | Сухановская | Юлия | Юрьевна | 01.10.2001 | 3 | Общая совместная собственность |
Как видим, у Ивановой Дарьи, Пугина Владислава и Анниной Любови нет зарегистрированных прав на недвижимость.
А что бы мы получили, используя внутреннее соединение Inner join? Как известно, оно исключает несовпадающие строки, поэтому три человека из нашей итоговой выборки просто бы выпали:
Запрос1 | ||||||
id | L_name | F_name | Middle_name | Birthday | id_realty | type |
3 | Евгеньин | Александр | Федерович | 30.04.1964 | 5 | Собственность |
5 | Герасимовская | Надежда | Павловна | 14.03.1992 | 4 | Общая долевая собственность |
6 | Герасимовский | Олег | Альбертович | 29. 01.1985 | 4 | Общая долевая собственность |
7 | Сухановский | Юрий | Андреевич | 25.09.1976 | 1 | Собственность |
7 | Сухановский | Юрий | Андреевич | 25.09.1976 | 3 | Общая совместная собственность |
8 | Сухановская | Юлия | Юрьевна | 01.10.2001 | 3 | Общая совместная собственность |
Казалось бы, второй вариант так же отвечает условиям нашей задачи. Однако, если мы дальше начнем присоединять еще и еще таблицы, три человека из результата уже безвозвратно исчезнут. Поэтому на практике при объединении множества таблиц намного чаще используются соединения Left и Right, чем Inner join.
Продолжим рассматривать с left join sql примеры. Присоединим таблицу с адресами наших объектов недвижимости:
SELECT Peoples.*, Realty_peoples.id_realty, Realty_peoples.type, Realty.address FROM Peoples LEFT JOIN Realty_peoples ON Peoples.id = Realty_peoples.id_peoples LEFT JOIN Realty ON Realty.id = Realty_peoples.id_realty |
Теперь мы получим не только вид права, но и адреса объектов недвижимости:
Запрос1 | |||||||
id | L_name | F_name | Middle_name | Birthday | id_realty | type | address |
1 | Иванова | Дарья | Борисовна | 16. 07.2000 | |||
2 | Пугин | Владислав | Николаевич | 29.01.1986 | |||
3 | Евгеньин | Александр | Федерович | 30.04.1964 | 5 | Собственность | г. Архангельск, пл. Терехина, д. 89, кв. 13 |
4 | Аннина | Любовь | Павловна | 31.12.1989 | |||
5 | Герасимовская | Надежда | Павловна | 14. 03.1992 | 4 | Общая долевая собственность | Архангельская область, г. Новодвинск, ул. Пролетарская, д. 16, кв. 137 |
6 | Герасимовский | Олег | Альбертович | 29.01.1985 | 4 | Общая долевая собственность | Архангельская область, г. Новодвинск, ул. Пролетарская, д. 16, кв. 137 |
7 | Сухановский | Юрий | Андреевич | 25.09.1976 | 3 | Общая совместная собственность | Архангельская область, г. Северодвинск, ул. Ленина, д. 134, кв. 85 |
7 | Сухановский | Юрий | Андреевич | 25. 09.1976 | 1 | Собственность | г. Архангельск, ул. Воронина, д. 7, кв.6 |
8 | Сухановская | Юлия | Юрьевна | 01.10.2001 | 3 | Общая совместная собственность | Архангельская область, г. Северодвинск, ул. Ленина, д. 134, кв. 85 |
Left join — типичные ошибки использования: неверный порядок таблиц
Основных ошибок, допускаемых при левом внешнем соединении таблиц, две:
- Неверно выбран порядок таблиц, из-за которого были потеряны данные.
- Ошибки при использовании Where в запросе с объединенными таблицами.
Рассмотрим ошибку первую. Перед решением любой задачи стоит четко понимать, что именно мы хотим получить в итоге. В рассматриваемом выше примере мы вывели всех до единого людей, но абсолютно потеряли сведения об объекте под номером 2, у которого собственника не нашлось.
Если бы мы переставили таблицы в запросе местами, и начали бы с «… From Realty left join Peoples…» то ни одну недвижимость мы бы не потеряли, чего не скажешь о людях.
Однако не стоит, испугавшись левого соединения, переходить на полное внешнее, которое включит в результате и совпадающие, и не совпадающие строки.
Ведь объем выборок зачастую очень велик, и лишние данные реально ни к чему. Главное — разобраться, что вы хотите в итоге получить: всех людей со списком имеющихся у них недвижимости, либо список всей недвижимости с их собственниками (если есть).
Left join — типичные ошибки использования: правильность запроса при задании условий в Where
Вторая ошибка также связана с потерей данных, причем не всегда сразу очевидной.
Вернемся к запросу, когда мы с помощью левого соединения получили данные по всем людям и имеющейся у них недвижимости. Вспомните следующий с применением left join sql пример:
FROM Peoples LEFT JOIN Realty_peoples ON Peoples. id = Realty_peoples.id_peoples; |
Допустим, мы хотим уточнить запрос и не выводить данные, где тип права – «Собственность». Если мы просто допишем, применяя left join sql, пример следующим условием:
…
Where type <> «Собственность» |
то потеряем данные по людям, у которых нет никакой недвижимости, ведь пустое значение Null не сравнивается таким образом:
Запрос1 | ||||||
id | L_name | F_name | Middle_name | Birthday | id_realty | type |
5 | Герасимовская | Надежда | Павловна | 14.03.1992 | 4 | Общая долевая собственность |
6 | Герасимовский | Олег | Альбертович | 29. 01.1985 | 4 | Общая долевая собственность |
7 | Сухановский | Юрий | Андреевич | 25.09.1976 | 3 | Общая совместная собственность |
8 | Сухановская | Юлия | Юрьевна | 01.10.2001 | 3 | Общая совместная собственность |
Чтобы предупредить появление ошибок по этой причине, лучше всего задать условие отбора сразу при соединении. Предлагаем рассмотреть следующий с left join sql пример.
SELECT Peoples.*, Realty_peoples.id_realty, Realty_peoples.type FROM Peoples LEFT JOIN Realty_peoples ON (Peoples. id = Realty_peoples.id_peoples AND type <> «Собственность») |
Результат будет следующим:
Запрос1 | ||||||
id | L_name | F_name | Middle_name | Birthday | id_realty | type |
1 | Иванова | Дарья | Борисовна | 16.07.2000 | ||
2 | Пугин | Владислав | Николаевич | 29.01.1986 | ||
3 | Евгеньин | Александр | Федерович | 30. 04.1964 | ||
4 | Аннина | Любовь | Павловна | 31.12.1989 | ||
5 | Герасимовская | Надежда | Павловна | 14.03.1992 | 4 | Общая долевая собственность |
6 | Герасимовский | Олег | Альбертович | 29.01.1985 | 4 | Общая долевая собственность |
7 | Сухановский | Юрий | Андреевич | 25. 09.1976 | 3 | Общая совместная собственность |
8 | Сухановская | Юлия | Юрьевна | 01.10.2001 | 3 | Общая совместная собственность |
Таким образом, выполнив простой с left join sql пример, мы получили список из всех людей, выведя дополнительно, у кого из них недвижимость в долевой/совместной собственности.
В качестве вывода хотелось бы еще раз подчеркнуть, что к выборке любой информации из базы данных нужно отнестись ответственно. Многие нюансы открыл перед нами с применением left join sql простой пример, объяснение которым одно – перед тем как приступить к составлению даже элементарного запроса, необходимо тщательно разобраться, что именно мы хотим получить в итоге. Удачи!
sql — Как правильно организовать синтаксис LEFT JOIN при объединении нескольких таблиц
Создайте представление (VIEW), которое будет объединять в себе все значения атрибутов по всем поставкам. Это представление должно включать в себя в денормализованной форме все данные по поставке из БД. Одна строка – одна поставка. Идентификаторы записей из таблиц, при помощи которых связываем таблицы соединениями (JOIN) в представление включать НЕ НАДО. Только фактические значения.
Таблица 1city — справочник городов
city_id Уникальный идентификатор города, первичный ключ
city_name Название города
state Штат, к которому относится город
population Население города
area Площадь города
Таблица 2 driver — справочник водителей
driver_id Уникальный идентификатор водителя, первичный ключ
first_name Имя водителя
last_name Фамилия водителя
address Адрес водителя
zip_code Почтовый индекс водителя
phone Телефон водителя
city_id Идентификатор города водителя, внешний ключ к таблице city
Таблица 3 customer — справочник клиентов
cust_id Уникальный идентификатор клиента, первичный ключ
cust_name Название клиента
annual_revenue Ежегодная выручка
cust_type Тип пользователя
address Адрес
zip Почтовый индекс
phone Телефон
city_id Идентификатор города, внешний ключ к таблице city
Таблица 4 truck — информация о грузовиках, на которых совершаются перевозки
truck_id Уникальный идентификатор грузовика, первичный ключ
make Производитель грузовика
model_year Дата выпуска грузовика
Таблица 5 shipment — доставки
ship_id integer Уникальный идентификатор доставки, первичный ключ
cust_id integer Идентификатор клиента, которому отправлена доставка, внешний ключ к таблице customer
weight numeric Вес посылки
truck_id integer Идентификатор грузовика,на котором отправлена доставка, внешний ключ к таблице truck
driver_id integer Идентификатор водителя, который осуществлял доставку, внешний ключ к таблице driver
city_id integer Идентификатор города в который совершена доставка, внешний ключ к таблице city
ship_date date Дата доставки
ниже пример моей организации кода. только начинаю изучать и не понимаю до конца, как правильно расположить всё. Что располагать в ON? На просторах интернета синтаксис только для двух таблиц нашла. или нужно еще подзапрос реализовывать?
create view aggregate5 AS select city_name, state,population, area, weight, ship_date, first_name, last_name, sql_driver.address as address_drive, zip_code, sql_driver.phone as phone_drive, make, model_year, cust_name, annual_revenue, cust_type, sql_customer.address as address_cust, zip, sql_customer.phone as phone_cust from sql_shipment, sql_customer, sql_city, sql_driver, sql_truck LEFT JOIN sql_shipment ON sql_shipment.ship_id=sql_customer.cust_id LEFT JOIN sql_customer on sql_customer.city_id=sql_city.city_id LEFT JOIN sql_city on sql_city.city_id=sql_customer.city_id LEFT JOIN sql_driver on sql_driver.driver_id= sql_shipment.driver_id LEFT JOIN sql_truck on sql_truck.truck_id=sql_shipment.truck_id where sql_shipment.cust_id=sql_customer.cust_id and sql_customer.city_id=sql_city.city_id and sql_shipment.driver_id=sql_driver.driver_id
SQL Left Join
В этой статье представлен обзор LEFT JOIN
в SQL, а также несколько основных примеров.
LEFT JOIN
или LEFT OUTER JOIN
возвращает строки, содержащие данные в левой таблице (слева от ключевого слова JOIN
), даже если в правой таблице нет соответствующих строк.
Синтаксис
Левое соединение указывается в предложении FROM
. Вы можете использовать либо LEFT JOIN
, либо LEFT OUTER JOIN 9.Синтаксис 0004.
Использование синтаксиса LEFT JOIN
:
SELECT * FROM Table1 LEFT JOIN Table2 ON Таблица1.Столбец = Таблица2.Столбец;
Использование синтаксиса LEFT OUTER JOIN
:
SELECT * FROM Table1 LEFT OUTER JOIN Table2 ON Таблица1.Столбец = Таблица2.Столбец;
Оба делают одно и то же. Просто ключевое слово OUTER
не является обязательным.
Примеры
Вот несколько примеров для демонстрации.
Sample Data
Во-первых, вот таблицы, которые мы будем использовать для примеров.
Таблица PetTypes
:
+-------------+-----------+ | Идентификатор типа питомца | Тип питомца | |-------------+------------| | 1 | Птица | | 2 | Кот | | 3 | Собака | | 4 | Кролик | +-------------+-----------+ (4 строки затронуты)
Таблица
:
+---------+-------------+---------- -+-----------+-------------+ | Идентификатор домашнего животного | Идентификатор типа питомца | Идентификатор владельца | Имя питомца | Дата рождения | |---------+--------------+-----------+------------+- -----------| | 1 | 2 | 3 | Пушистый | 20.11.2020 | | 2 | 3 | 3 | Получить | 2019-08-16 | | 3 | 2 | 2 | Скретч | 2018-10-01 | | 4 | 3 | 3 | Виляние | 2020-03-15 | | 5 | 1 | 1 | Твитнуть | 2020-11-28 | | 6 | 3 | 4 | Пушистый | 2020-09-17 | | 7 | 3 | 2 | Кора | NULL | | 8 | 2 | 4 | Мяу | NULL | +---------+-------------+-----------+------------+- -----------+ (затронуто 8 строк)
Таблица Владельцы
:
+-----------+-------------+------------+-------- ----------------------+-----+ | Идентификатор владельца | Имя | Фамилия | Телефон | Электронная почта | |-----------+-------------+-------------+---------- ------+-------------------| | 1 | Гомер | Коннери | (308) 555-0100 | [электронная почта защищена] | | 2 | Барт | Питт | (231) 465-3497 | [электронная почта защищена] | | 3 | Нэнси | Симпсон | (489) 591-0408 | NULL | | 4 | Борис | Трамп | (349) 611-8908 | NULL | | 5 | Вуди | Иствуд | (308) 555-0112 | [электронная почта защищена] | +-----------+-------------+------------+---------- ------+-------------------+
Обратите внимание, что:
- Столбец
PetTypeId
таблицыPets
является внешним ключомPetTypeId
таблицыPetTypes
(которая является первичным ключом этой таблицы). - Столбец
OwnerId
таблицыPets
является внешним ключомСтолбец OwnerId
таблицыOwners
.
Запрос левого соединения
Вот пример выполнения левого соединения для двух из этих таблиц.
ВЫБОР п.имя питомца, pt.PetType ОТ PetTypes pt LEFT JOIN Домашние животные p ON p.PetTypeId = pt.PetTypeId;
Результат:
+-----------+-----------+ | Имя питомца | Тип питомца | |-----------+------------| | Твитнуть | Птица | | Пушистый | Кот | | Скретч | Кот | | Мяу | Кот | | Получить | Собака | | Виляние | Собака | | Пушистый | Собака | | Кора | Собака | | NULL | Кролик | +-----------+------------+ (9затронутых строк)
Левое соединение приводит к тому, что мы получаем значение PetType
, которое не соответствует PetName
. Кроликов в качестве домашних животных нет. Но левое соединение приводит к возврату Rabbit
, хотя в таблице Pets
этого типа нет питомцев. Это приводит к значению NULL
в столбце PetName
против Rabbit
.
Это произошло только потому, что Кролик
находился в левой таблице (т.е. слева от ЛЕВОЕ СОЕДИНЕНИЕ
ключевых слов). Хорошо, мое форматирование делает его скорее «сверху», чем «слева», но вы поняли.
Вот что произойдет, если мы поменяем порядок таблиц в нашем запросе.
ВЫБОР п.имя питомца, pt.PetType С домашними животными р LEFT JOIN PetTypes pt ON p.PetTypeId = pt.PetTypeId;
Результат:
+-----------+-----------+ | Имя питомца | Тип питомца | |-----------+------------| | Пушистый | Кот | | Получить | Собака | | Скретч | Кот | | Виляние | Собака | | Твитнуть | Птица | | Пушистый | Собака | | Кора | Собака | | Мяу | Кот | +-----------+------------+ (затронуто 8 рядов)
На этот раз Кролика
не вернули. Это потому, что его таблица ( PetTypes
) находилась с правой стороны соединения.
Нам нужно изменить его на правое соединение или полное соединение, если мы хотим, чтобы Rabbits
возвращались с использованием этого порядка таблиц.
Левое соединение для 3 таблиц
Вот пример выполнения левого соединения для всех трех таблиц.
ВЫБОР п.имя питомца, pt.PetType, CONCAT(o.FirstName, ' ', o.LastName) AS PetOwner ОТ владельцев o ВЛЕВО ПРИСОЕДИНЯЙТЕСЬ к домашним животным p ON p.OwnerId = o.OwnerId LEFT JOIN PetTypes pt ON p.PetTypeId = pt.PetTypeId;
Результат:
+-----------+-----------+----------------+ | Имя питомца | Тип питомца | PetOwner | |-----------+------------+----------------| | Твитнуть | Птица | Гомер Коннери | | Скретч | Кот | Барт Питт | | Кора | Собака | Барт Питт | | Пушистый | Кот | Нэнси Симпсон | | Получить | Собака | Нэнси Симпсон | | Виляние | Собака | Нэнси Симпсон | | Пушистый | Собака | Борис Трамп | | Мяу | Кот | Борис Трамп | | NULL | NULL | Вуди Иствуд | +-----------+------------+----------------+ (9строки затронуты)
На этот раз у нас есть владелец домашнего животного, у которого нет домашнего животного.
Мы могли бы снова перетасовать порядок столов и получить другой результат.
ВЫБОР п.имя питомца, pt.PetType, CONCAT(o.FirstName, ' ', o.LastName) AS PetOwner FROM PetTypes pt LEFT JOIN Pets p ON p.PetTypeId = pt.PetTypeId LEFT JOIN Владельцы o ON p.OwnerId = o.OwnerId;
Результат:
+-----------+-----------+---------------+ | Имя питомца | Тип питомца | Владелец домашнего животного | |-----------+------------+----------------| | Твитнуть | Птица | Гомер Коннери | | Пушистый | Кот | Нэнси Симпсон | | Скретч | Кот | Барт Питт | | Мяу | Кот | Борис Трамп | | Получить | Собака | Нэнси Симпсон | | Виляние | Собака | Нэнси Симпсон | | Пушистый | Собака | Борис Трамп | | Кора | Собака | Барт Питт | | NULL | Кролик | | +-----------+------------+---------------+ (9строки затронуты)
На этот раз мы получили дополнительный тип питомца ( Кролик
), но не дополнительного владельца.
Если вам интересно, почему последний PetOwner
не является NULL
(как последний PetName
), это потому, что это результат конкатенации строк. Я использовал функцию T-SQL CONCAT()
для объединения имени и фамилии владельца.
ЛЕВОЕ СОЕДИНЕНИЕ, ПРАВОЕ СОЕДИНЕНИЕ Операции
Access для Microsoft 365 Access 2021 Access 2019Access 2016 Access 2013 Access 2010 Access 2007 Больше...Меньше
Объединяет записи исходной таблицы при использовании в любом предложении FROM.
Синтаксис
ИЗ таблица 1 [ ВЛЕВО | RIGHT] JOIN table2
ON table1.field1 compopr table2.field2
Операции LEFT JOIN и RIGHT JOIN состоят из следующих частей:
Деталь | Описание |
таблица1 , таблица2 | Имена таблиц, из которых объединяются записи. |
поле1 , поле2 | Имена объединяемых полей. Поля должны иметь один и тот же тип данных и содержать одинаковые данные, но они не обязательно должны иметь одно и то же имя. |
композит | Любой оператор реляционного сравнения: «=», «<», «>», «<=», «>=» или «<>». |
Замечания
Используйте операцию LEFT JOIN для создания левого внешнего соединения. Левые внешние соединения включают все записи из первой (левой) из двух таблиц, даже если нет совпадающих значений для записей во второй (правой) таблице.
Используйте операцию RIGHT JOIN для создания правильного внешнего соединения. Правое внешнее соединение включает все записи из второй (правой) из двух таблиц, даже если нет совпадающих значений для записей в первой (левой) таблице.
Например, вы можете использовать LEFT JOIN с таблицами «Отделы» (слева) и «Сотрудники» (справа), чтобы выбрать все отделы, включая те, которым не назначены сотрудники. Чтобы выбрать всех сотрудников, включая тех, кто не относится к отделу, вы должны использовать RIGHT JOIN.
В следующем примере показано, как можно соединить таблицы "Категории" и "Продукты" в поле "Код категории". Запрос выдает список всех категорий, включая те, которые не содержат товаров:
.ВЫБЕРИТЕ CategoryName, ProductName FROM Categories LEFT JOIN Products ON Categories.CategoryID = Products.CategoryID;
В этом примере CategoryID является присоединяемым полем, но оно не включается в результаты запроса, поскольку оно не включено в инструкцию SELECT.