SQL – Основы выборки данных – Часть 2

Группировка данных и агрегатные функции (Group By)

Иногда требуется узнать информацию не о самих объектах, а об определенных группах, которые они образуют. Для этого используется оператор GROUP BY и агрегатные функции.

Общая структура запроса

SELECT – поля_таблиц

FROM – список_таблиц

GROUP BY -поля_группировки

Пример использования

Для демонстрации работы оператора GROUP BY выведем общую сумму потраченных средств, сгруппированных по членам семьи.

SELECT family_member, SUM(unit_price * amount)
FROM Payments
GROUP BY family_member

Как это работает:

family_memberunit_priceamount
120001
221001
3205
4350 1
41002
51501
21201
Набор данных, находящихся в таблице Payments

Для того, чтобы лучше понять как происходит группировка по полю, преобразуем исходные данные в новый, сгруппированный вид:

family_memberunit_priceamount
120001
 3001
 103
 7 5
 88
221001
 505
Сгруппированный вид

После этого мы можем внутри каждой из этих групп применить формулу суммы, которая умножит количество товара на его стоимость, а потом просуммирует все получившиеся значения:

family_memberSUM(unit_price*amount)
12504
274194
33600
4650
51060
Результат запроса

Агрегатные функции

Агрегатная функция выполняет вычисление на наборе значений и возвращает одиночное значение.

Агрегатные функции применяются для значений, не равных NULL. Исключением является функция COUNT().

ФункцияОписание
SUM(поля_таблицы)Возвращает сумму значений
AVG(поля_таблицы)Возвращает среднее значение
COUNT(поля_таблицы)Возвращает количество записей
MIN(поля_таблицы)Возвращает минимальное значение
MAX(поля_таблицы)Возвращает максимальное значение
Агрегатные функции

Having

Для фильтрации строк по значениям агрегатных функций используется оператор HAVING.

Общая структура запроса

SELECT – поля_таблиц

FROM – список_таблиц

GROUP BY -поля_группировки

HAVING – условия_на_ограничение_строк_после_группировки

Отличие HAVING от WHERE:

  • WHERE — сначала выбираются записи по условию, а затем могут быть сгруппированы, отсортированы и т.д.
  • HAVING — сначала группируются записи, а затем выбираются по условию, при этом, в отличие от WHERE, в нём можно использовать значения агрегатных функций

Пример использования

Выведем общую сумму, потраченную на покупки, для каждого члена семьи, где общая сумма покупки меньше, чем 5000

SELECT family_member, SUM(unit_price * amount) AS sum
FROM Payments
GROUP BY family_member
HAVING sum < 5000

Ссылка на задачи для проверки, которые мы проходили во время урока.

Многотабличные запросы, оператор JOIN

До этого мы рассматривали работу только с одной таблице. В реальности, чаще всего приходится делать выборку из нескольких таблиц, каким-то образом объединяя их. Для их объединения используется оператор JOIN.

Общая структура запроса

SELECT – поля_таблиц

FROM – таблица_1

[INNER] | [[LEFT | RIGHT | FULL] [OUTER]] JOIN – таблица_2

ON – условие_соединения

[[INNER] | [[LEFT | RIGHT | FULL] [OUTER]] JOIN – таблица_n

ON – условие_соединения

Соединение бывает внутренним (INNER) или внешним (OUTER), при этом внешнее соединение делится на левое (LEFT), правое (RIGHT) и полное (FULL).

INNER JOIN

По умолчанию, если не указаны какие-либо параметры, JOIN выполняется как INNER JOIN, то есть как внутреннее (перекрёстное) соединение таблиц.Внутреннее соединение — соединение двух таблиц, при котором каждая запись из первой таблицы соединяется с каждой записью второй таблицы, создавая тем самым все возможные комбинации записей обеих таблиц.

Например, объединим таблицы покупок (Payments) и членов семьи (FamilyMembers) таким образом, чтобы дополнить каждую покупку данными о том, кто её совершил.

payment_iddatefamily_membergoodamountunit_price
12005-02-121112000
22005-03-232112100
32005-05-1434520
42005-07-22451350
52005-07-26472150
Таблица Payments

member_idstatusmember_namebirthday
1fatherHeadley Quincey1960-05-13
2motherFlavia Quincey1963-02-16
3sonAndie Quincey1983-06-05
4daughterLela Quincey1985-06-07
5daughterAnnie Quincey1988-04-10
Таблица FamilyMembers

Для того, чтобы решить поставленную задачу выполним запрос, который объединяет поля строки из одной таблицы с полями другой, если выполняется условие, что покупатель товара (family_member) совпадает с идентификатором члена семьи (member_id):

SELECT *
FROM Payments
JOIN FamilyMembers ON family_member = member_id

В результате можно увидеть, что каждая строка из таблицы Payments дополнилась данными о члене семьи, который совершил покупку.

payment_iddatefamily_membergoodamountunit_pricemember_idstatusmember_namebirthday
12005-02-1211120001fatherHeadley Quincey1960-05-13
22005-03-2321121002motherFlavia Quincey1963-02-16
32005-05-14345203sonAndie Quincey1983-06-05
42005-07-224513504daughterLela Quincey1985-06-07
52005-07-264721504daughterLela Quincey1985-06-07

Для внутреннего соединения таблиц также можно использовать оператор WHERE. Например, вышеприведённый запрос, написанный с помощью INNER JOIN, будет выглядеть так:

SELECT *
FROM Payments, FamilyMembers
WHERE family_member = member_id

Внешнее соединение может быть трёх типов: левое (LEFT), правое (RIGHT) и полное (FULL). По умолчанию оно является полным.

Главным отличием внешнего соединения от внутреннего является то, что оно обязательно возвращает все строки одной (LEFT, RIGHT) или двух таблиц (FULL).

Внешнее левое соединение (LEFT OUTER JOIN)

Для примера получим из базы данных расписание звонков объединённых с соответствующими занятиями в расписании занятий:

SELECT *

FROM Timepair

    LEFT JOIN Schedule ON Schedule.number_pair = Timepair.id;

idstart_pairend_pair
108:30:0009:15:00
209:20:0010:05:00
310:15:0011:00:00
411:05:0011:50:00
512:50:0013:35:00
Данные в таблице Timepair
iddateclassnumber_pairteachersubjectclassroom
12019-09-019111147
42019-09-02914313
72019-09-03915636
102019-09-04919939
132019-09-059131343
Данные в таблице Schedule

В выборку попали все строки из левой таблицы, дополненные данными о занятиях.

timepair.idstart_pairend_pairschedule.iddateclassnumber_pairteachersubjectclassroom
108:3009:1542019-09-02914313
108:3009:1572019-09-03915636
108:3009:15162019-08-30919434
108:3009:15102019-09-049111939
209:2010:0522019-09-01928147
209:2010:0552019-09-029221343

Внешнее правое соединение (RIGHT OUTER JOIN)

Соединение, которое возвращает все значения из правой таблицы, соединённые с соответствующими значениями из левой таблицы.

Внешнее полное соединение (FULL OUTER JOIN)

Соединение, которое выполняет внутреннее соединение записей и дополняет их левым внешним соединением и правым внешним соединением.

Алгоритм работы полного соединения:

  1. Формируется таблица на основе внутреннего соединения (INNER JOIN).
  2. В таблицу добавляются значения не вошедшие в результат формирования из левой таблицы (LEFT OUTER JOIN).
  3. В таблицу добавляются значения не вошедшие в результат формирования из правой таблицы (RIGHT OUTER JOIN).

Базовые запросы для разных вариантов объединения таблиц

СхемаЗапрос с JOIN
 Получение всех данных из левой таблицы, соединённых с соответствующими данными из правой:
SELECT поля_таблиц
FROM левая_таблица LEFT JOIN правая_таблица  
  ON правая_таблица.ключ = левая_таблица.ключ
 Получение всех данных из правой таблицы, соединённых с соответствующими данными из левой:
SELECT поля_таблиц
FROM левая_таблица RIGHT JOIN правая_таблица    
ON правая_таблица.ключ = левая_таблица.ключ
Получение данных, относящихся только к левой таблице:
SELECT поля_таблиц
FROM левая_таблица LEFT JOIN правая_таблица
    ON правая_таблица.ключ = левая_таблица.ключ
WHERE правая_таблица.ключ IS NULL
Получение данных, относящихся только к правой таблице:
SELECT поля_таблиц
FROM левая_таблица RIGHT JOIN правая_таблица
    ON правая_таблица.ключ = левая_таблица.ключ
WHERE левая_таблица.ключ IS NULL
Получение всех данных, относящихся к левой и правой таблицам, а также их внутреннему соединению:
SELECT поля_таблиц 
FROM левая_таблица FULL OUTER JOIN правая_таблица
    ON правая_таблица.ключ = левая_таблица.ключ
Получение всех данных, относящихся к левой и правой таблицам, а также их внутреннему соединению:
SELECT поля_таблиц 
FROM левая_таблица FULL OUTER JOIN правая_таблица
    ON правая_таблица.ключ = левая_таблица.ключ
Получение данных, не относящихся к левой и правой таблицам одновременно (обратное INNER JOIN):
SELECT поля_таблиц 
FROM левая_таблица FULL OUTER JOIN правая_таблица
    ON правая_таблица.ключ = левая_таблица.ключ
WHERE левая_таблица.ключ IS NULL
    OR правая_таблица.ключ IS NULL

Ссылка на задачи для проверки, которые мы проходили во время урока.

Rudchenko Yuliya

Автор: Rudchenko Yuliya