Связи таблиц и агрегация
До этого мы работали с одной таблицей. Но настоящая база данных состоит из множества таблиц, связанных друг с другом. Студенты — в одной таблице, группы — в другой, оценки — в третьей. И самое интересное начинается, когда мы хотим получить данные из нескольких таблиц сразу.
JOIN, считать статистику (COUNT, SUM, AVG, MIN, MAX), группировать данные через GROUP BY и фильтровать группы через HAVING. Это основа любых отчётов и аналитики.
План лекции
Сегодня мы пройдём путь от «как связать таблицы» до «как построить отчёт».
- 1 Зачем нужны связи между таблицами
- 2 Что такое JOIN и как он работает
- 3 INNER JOIN — только совпадения
- 4 LEFT JOIN и RIGHT JOIN — с сохранением «сирот»
- 5 FULL JOIN — объединение с двух сторон
- 6 Сравнение всех JOIN
- 7 Агрегатные функции: COUNT, SUM, AVG, MIN, MAX
- 8 GROUP BY — группировка данных
- 9 HAVING — фильтрация групп
- 10 Порядок выполнения запроса
- 11 Типичные ошибки
- 12 Практика и домашнее задание
SELECT и внешних ключей эта тема будет непонятна.Зачем нужны связи между таблицами
Представьте, что у нас есть только одна таблица. В ней хранятся студенты и их группы.
Проблема: название группы повторяется у каждого студента. Если группу переименуют, нужно менять все строки. Если студентов станет 10 000 — это огромный риск ошибок.
GroupId — ссылку на группу. Именно для этого существует внешний ключ FOREIGN KEY, который мы изучили на прошлой лекции.
Что такое JOIN?
JOIN (по-английски «соединение», «объединение») — это команда SQL, которая объединяет строки из двух и более таблиц в один результат.
Идея простая: мы говорим СУБД (системе управления базами данных), что Students.GroupId — это ссылка на Groups.Id. И СУБД сама находит, какие строки совпадают.
Подготовка: две таблицы
Создадим две связанные таблицы и заполним их данными. Это база для всех примеров.
GroupId = NULL. Он пока не распределён в группу. Это пригодится нам при изучении LEFT JOIN.INNER JOIN — только совпадения
INNER JOIN (внутреннее соединение) возвращает только те строки, для которых есть совпадение в обеих таблицах.
Результат:
GroupId = NULL, и совпадения в таблице Groups нет.Разбор синтаксиса INNER JOIN
Разберём каждую часть запроса по шагам.
s и g нужны, потому что у обеих таблиц есть столбец Name. Без псевдонимов СУБД не поймёт, какой Name имеется в виду.LEFT JOIN — все левые и совпадения
LEFT JOIN (левое соединение) возвращает все строки левой таблицы плюс совпадения из правой. Если совпадения нет — правые столбцы будут NULL.
Результат:
RIGHT JOIN — все правые и совпадения
RIGHT JOIN (правое соединение) — зеркальное отражение LEFT JOIN. Возвращает все строки правой таблицы плюс совпадения из левой.
Результат:
Groups была группа без студентов — она бы появилась в результате с Name = NULL.FULL JOIN — все с двух сторон
FULL JOIN (полное соединение) возвращает все строки из обеих таблиц. Там, где нет совпадения, будут NULL.
Результат:
Groups была группа без студентов, она бы тоже попала в результат с Name = NULL. FULL JOIN используется редко — но полезен для поиска «сирот» с обеих сторон.Сравнение всех JOIN
Соберём все виды соединений в одну таблицу.
INNER JOIN или LEFT JOIN. Остальные — реже.Агрегатные функции — обзор
Агрегатные функции — это функции, которые берут много строк и возвращают одно значение. По-русски: «агрегируют», то есть «собирают» данные.
COUNT — сколько строк
COUNT — самая частая агрегатная функция. Считает количество строк.
COUNT(*) считает все строки, включая с NULL. COUNT(столбец) не считает строки, где столбец равен NULL. Это важное различие.SUM, AVG, MIN, MAX
Остальные агрегатные функции работают с числами.
GROUP BY — группировка данных
GROUP BY (по-русски «сгруппировать по») разбивает строки на группы по какому-то признаку, а затем применяет агрегатные функции к каждой группе отдельно.
Результат:
GROUP BY мы получили бы просто «5 студентов». С GROUP BY — «2 в первой группе, 1 во второй, 1 в третьей, 1 без группы».GROUP BY + JOIN — самый частый случай
Обычно GROUP BY используется вместе с JOIN, чтобы показать не GroupId, а название группы.
Результат:
LEFT JOIN, чтобы группы без студентов тоже попали в результат (с 0). С INNER JOIN они бы пропали.HAVING — фильтрация групп
HAVING — это «WHERE для групп». WHERE фильтрует отдельные строки, а HAVING — уже сгруппированные результаты.
Результат:
HAVING используется агрегатная функция COUNT(s.Id), а не просто столбец. Это ключевое отличие HAVING от WHERE.WHERE vs HAVING
Разница простая: WHERE работает до группировки, HAVING — после.
WHERE. Если по результатам агрегации (сумма, среднее, количество) — HAVING.WHERE и HAVING вместе
Их можно комбинировать: сначала WHERE отфильтрует строки, потом GROUP BY сгруппирует, потом HAVING отфильтрует группы.
WHERE — оставили только студентов старше 24.2.
GROUP BY — сгруппировали по группам.3.
HAVING — оставили только те группы, где таких студентов больше одного.
Порядок выполнения запроса
SQL выполняется не сверху вниз, а в строгом порядке. Важно понимать, что происходит на каждом шаге.
WHERE не может использовать агрегатные функции, а HAVING может. И почему псевдоним из SELECT иногда недоступен в WHERE.Практический пример: отчёт по группам
Соберём всё вместе: полный отчёт по группам с количеством и средним возрастом.
Результат:
Типичные ошибки новичков
INNER JOIN Groups g без ON ... — это декартово произведение (все строки со всеми). Результат огромный и бессмысленный.Пытаетесь выбрать
GroupId и COUNT(*) без GROUP BY — ошибка. Нужно сгруппировать.Пытаетесь отфильтровать группы через
WHERE COUNT(*) > 1 — ошибка. Для агрегатов только HAVING.Это разрешено, но
HAVING без GROUP BY работает как WHERE с одной группой. Обычно это ошибка.Теряются «сироты». Если нужны все из основной таблицы —
LEFT JOIN.AVG(Age) не учитывает строки с Age = NULL. Среднее считается по меньшему числу строк.Практика: 5 задач
Попробуйте выполнить эти запросы в SSMS. Если не получилось — смотрите подсказки на предыдущих слайдах.
Задача 1
Выведите всех студентов с названием их группы (используйте INNER JOIN).
Задача 2
Выведите всех студентов, включая тех, у кого нет группы (используйте LEFT JOIN).
Задача 3
Посчитайте, сколько студентов в каждой группе.
Задача 4
Найдите средний возраст студентов в каждой группе.
Задача 5
Выведите только те группы, где больше одного студента, отсортировав по количеству по убыванию.
Шпаргалка
Сохраните этот слайд — здесь все команды, которые мы изучили.
Итоги лекции
Подведём итоги. Вот что вы теперь знаете.
- ✅ JOIN — соединение таблиц по общему признаку.
- ✅ INNER JOIN — только совпадения.
- ✅ LEFT JOIN — все из левой + совпадения.
- ✅ RIGHT JOIN — все из правой + совпадения.
- ✅ FULL JOIN — все из обеих.
- ✅ COUNT, SUM, AVG, MIN, MAX — агрегатные функции.
- ✅ GROUP BY — группировка строк.
- ✅ HAVING — фильтрация групп (аналог WHERE для агрегатов).
- ✅ Порядок выполнения: FROM → JOIN → WHERE → GROUP BY → HAVING → SELECT → ORDER BY.
SELECT, JOIN, GROUP BY.Домашнее задание
Задания для самостоятельной работы. Первые три обязательны, остальные — для оценки «отлично».
- Создайте таблицы
AuthorsиBooksс внешним ключом (см. Лекцию 2). - Добавьте 3 авторов и 5 книг.
- Напишите запрос: «все книги с именами авторов» через
INNER JOIN. - Напишите запрос: «все авторы, даже без книг» через
LEFT JOIN. - Посчитайте, сколько книг у каждого автора.
- Найдите авторов, у которых больше одной книги.
Что дальше?
Мы прошли всю теоретическую часть по SQL. Дальше — практика.
- Практика 1: создание базы «Библиотека» в MS SQL Server через SSMS. Таблицы, ключи, тестовые данные, запросы.
- Практика 2: подключение Java к MS SQL Server через JDBC. Драйвер, подключение, чтение и запись данных.
Спасибо за внимание!
🔗
JOIN и агрегация — это то, что делает SQL мощным
Теперь вы умеете соединять таблицы, считать статистику и строить отчёты — как настоящий аналитик данных.