В любой реальной реляционной базе данных вся информация распределяется по отдельным таблицам. Многие из таблиц имеют зафиксированные в схеме установленные связи друг с другом. Однако с помощью запросов 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 простой пример, объяснение которым одно – перед тем как приступить к составлению даже элементарного запроса, необходимо тщательно разобраться, что именно мы хотим получить в итоге. Удачи!