HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-26
1 <p>Реляционная модель подразумевает связь между данными разных отношений посредством внешних ключей. С практической точки зрения это можно сформулировать так - зная первичный ключ одной сущности, мы можем извлечь связанные с ней данные из другой сущности.</p>
1 <p>Реляционная модель подразумевает связь между данными разных отношений посредством внешних ключей. С практической точки зрения это можно сформулировать так - зная первичный ключ одной сущности, мы можем извлечь связанные с ней данные из другой сущности.</p>
2 <p>В простых ситуациях данные извлекаются так:</p>
2 <p>В простых ситуациях данные извлекаются так:</p>
3 <p>Но есть множество ситуаций, где простой выборкой не обойтись. Для этого нужна операция JOIN, которую мы изучим в этом уроке.</p>
3 <p>Но есть множество ситуаций, где простой выборкой не обойтись. Для этого нужна операция JOIN, которую мы изучим в этом уроке.</p>
4 <h2>JOIN</h2>
4 <h2>JOIN</h2>
5 <p>Для примера попробуем найти всех пользователей Хекслета, которые ни разу не создавали топики. На текущий момент мы знаем ровно один способ выполнить эту задачу. Нужно выполнить два шага:</p>
5 <p>Для примера попробуем найти всех пользователей Хекслета, которые ни разу не создавали топики. На текущий момент мы знаем ровно один способ выполнить эту задачу. Нужно выполнить два шага:</p>
6 <ol><li><p>Извлечь из базы всех пользователей, которые создали хотя бы один топик:</p>
6 <ol><li><p>Извлечь из базы всех пользователей, которые создали хотя бы один топик:</p>
7 </li>
7 </li>
8 <li><p>Найти всех пользователей, у которых идентификаторы не совпадают со списком user_id, полученном на предыдущем этапе:</p>
8 <li><p>Найти всех пользователей, у которых идентификаторы не совпадают со списком user_id, полученном на предыдущем этапе:</p>
9 </li>
9 </li>
10 </ol><p>Задача будет решена, но есть одна проблема. Идентификаторов может быть очень много. Гонять такое количество записей из базы в код и обратно - не самая разумная идея.</p>
10 </ol><p>Задача будет решена, но есть одна проблема. Идентификаторов может быть очень много. Гонять такое количество записей из базы в код и обратно - не самая разумная идея.</p>
11 <h2>INNER JOIN</h2>
11 <h2>INNER JOIN</h2>
12 <p>Теперь рассмотрим следующую задачу - найти записи о пользователях в одной таблице, для которых нет записей о топиках в другой таблице.</p>
12 <p>Теперь рассмотрим следующую задачу - найти записи о пользователях в одной таблице, для которых нет записей о топиках в другой таблице.</p>
13 <p>Реляционная алгебра позволяет выполнить эту операцию с помощью соединения JOIN, используя ровно один запрос. Начнем знакомство с JOIN на таком примере, в котором мы найдем имена всех пользователей, создавших хотя бы один топик</p>
13 <p>Реляционная алгебра позволяет выполнить эту операцию с помощью соединения JOIN, используя ровно один запрос. Начнем знакомство с JOIN на таком примере, в котором мы найдем имена всех пользователей, создавших хотя бы один топик</p>
14 <p>Результатом такого запроса станет выборка, в которую попали поля обеих таблиц. Здесь соединяются две таблицы: users и topics по условию users.id = topics.user_id. Это важное условие для правильной работы.</p>
14 <p>Результатом такого запроса станет выборка, в которую попали поля обеих таблиц. Здесь соединяются две таблицы: users и topics по условию users.id = topics.user_id. Это важное условие для правильной работы.</p>
15 <p>В нашем примере отношения связаны внешним ключом: соответственно, при объединении этих таблиц нужно явно указать, как мы их соединяем. Общий синтаксис выглядит так:</p>
15 <p>В нашем примере отношения связаны внешним ключом: соответственно, при объединении этих таблиц нужно явно указать, как мы их соединяем. Общий синтаксис выглядит так:</p>
16 <p>На самом деле общая форма сложнее, потому что объединять можно произвольное число таблиц. Другими словами, условий соединения может быть много.</p>
16 <p>На самом деле общая форма сложнее, потому что объединять можно произвольное число таблиц. Другими словами, условий соединения может быть много.</p>
17 <p>JOIN - это сокращенная версия соединения INNER JOIN, то есть внутреннего соединения.</p>
17 <p>JOIN - это сокращенная версия соединения INNER JOIN, то есть внутреннего соединения.</p>
18 <p>В эту выборку попадают только те записи, для которых есть соответствие в другой таблице. Причем, если у одного пользователя пять топиков, то в выборке окажутся все пять строк. Такой запрос имеет смысл делать на странице вывода топиков, что позволит к каждому топику сразу же вывести нужную информацию и о самом пользователе.</p>
18 <p>В эту выборку попадают только те записи, для которых есть соответствие в другой таблице. Причем, если у одного пользователя пять топиков, то в выборке окажутся все пять строк. Такой запрос имеет смысл делать на странице вывода топиков, что позволит к каждому топику сразу же вывести нужную информацию и о самом пользователе.</p>
19 <p>Запросы с соединениями порождают одну небольшую проблему. В примере выше часть SELECT содержит только те поля, имена которых уникальны среди всех полей обеих таблиц. Соответственно, при выборке не возникает неоднозначностей.</p>
19 <p>Запросы с соединениями порождают одну небольшую проблему. В примере выше часть SELECT содержит только те поля, имена которых уникальны среди всех полей обеих таблиц. Соответственно, при выборке не возникает неоднозначностей.</p>
20 <p>Если выполнить этот же запрос со звездочкой, то в выборку попадут поля, у которых одинаковые названия, что создаст сложности при анализе данных уже в коде приложения. А при выполнении запроса с указанием дублирующихся полей вообще возникнет ошибка:</p>
20 <p>Если выполнить этот же запрос со звездочкой, то в выборку попадут поля, у которых одинаковые названия, что создаст сложности при анализе данных уже в коде приложения. А при выполнении запроса с указанием дублирующихся полей вообще возникнет ошибка:</p>
21 <p>В таких случаях спасают псевдонимы и возможность указывать таблицу для каждого поля:</p>
21 <p>В таких случаях спасают псевдонимы и возможность указывать таблицу для каждого поля:</p>
22 <h2>LEFT JOIN</h2>
22 <h2>LEFT JOIN</h2>
23 <p>Пока мы все еще не можем решить нашу исходную задачу. Для этого понадобится операция левого соединения LEFT JOIN:</p>
23 <p>Пока мы все еще не можем решить нашу исходную задачу. Для этого понадобится операция левого соединения LEFT JOIN:</p>
24 <p>LEFT JOIN берет все данные из одной таблицы и присоединяет к ним данные из другой, если они присутствуют. Если нет, то заполняет их NULL. Чисто технически этот запрос отличается только тем, что добавляется слово LEFT:</p>
24 <p>LEFT JOIN берет все данные из одной таблицы и присоединяет к ним данные из другой, если они присутствуют. Если нет, то заполняет их NULL. Чисто технически этот запрос отличается только тем, что добавляется слово LEFT:</p>
25 <p>LEFT JOIN полезен, когда нам нужно работать со всеми данными одной таблицы и связанными с ними записями, если они есть. Если их нет, то ничего страшного, мы все равно хотим получить данные из первой таблицы.</p>
25 <p>LEFT JOIN полезен, когда нам нужно работать со всеми данными одной таблицы и связанными с ними записями, если они есть. Если их нет, то ничего страшного, мы все равно хотим получить данные из первой таблицы.</p>
26 <p>Этот запрос все еще не возвращает нам то, что мы хотели изначально - записи о пользователях, которые не оставили ни одного топика на Хекслете. Чтобы закончить решение, нужно добавить в выборку условие WHERE:</p>
26 <p>Этот запрос все еще не возвращает нам то, что мы хотели изначально - записи о пользователях, которые не оставили ни одного топика на Хекслете. Чтобы закончить решение, нужно добавить в выборку условие WHERE:</p>
27 <p>Запросы на соединение могут быть как очень простыми, так и очень сложными. Они могут занимать несколько экранов текста и включать в себя сразу множество таблиц. В этом уроке мы лишь немного затронули эту тему и познакомились с самой концепцией, остальное познается во время экспериментов в рабочих и тестовых проектах.</p>
27 <p>Запросы на соединение могут быть как очень простыми, так и очень сложными. Они могут занимать несколько экранов текста и включать в себя сразу множество таблиц. В этом уроке мы лишь немного затронули эту тему и познакомились с самой концепцией, остальное познается во время экспериментов в рабочих и тестовых проектах.</p>