Гранулярность результата и уникальность ключа
Содержание курса
Заказы и клиенты: почему в отчёте разное число строк
Подготовим две таблицы в SQLite: справочник клиентов и список их покупок.
CREATE TABLE clients(
client_id INTEGER PRIMARY KEY,
client_name TEXT
);
CREATE TABLE orders(
order_id INTEGER PRIMARY KEY,
client_id INTEGER,
order_date TEXT,
total INTEGER
);
INSERT INTO clients VALUES
(1, 'Анна'),
(2, 'Борис'),
(3, 'Вера');
INSERT INTO orders VALUES
(101, 1, '2024-01-10', 1000),
(102, 1, '2024-01-15', 2000),
(103, 2, '2024-01-12', 1500);
В таблице clients лежат три клиента. В таблице orders лежат три заказа: два принадлежат Анне, один — Борису. У Веры заказов нет.
Соединим обе таблицы обычным INNER JOIN:
SELECT
c.client_id,
c.client_name,
o.order_id,
o.order_date,
o.total
FROM clients c
JOIN orders o ON o.client_id = c.client_id
ORDER BY o.order_id;
Запрос возвращает 3 строки:
| client_id | client_name | order_id | order_date | total |
|---|---|---|---|---|
| 1 | Анна | 101 | 2024-01-10 | 1000 |
| 1 | Анна | 102 | 2024-01-15 | 2000 |
| 2 | Борис | 103 | 2024-01-12 | 1500 |
Здесь каждая строка показывает один оформленный заказ. Так как у Анны два заказа, строка с её именем выведена дважды.
Теперь сгруппируем заказы по клиентам и посчитаем сумму покупок:
SELECT
c.client_id,
c.client_name,
SUM(o.total) AS total_spent
FROM clients c
JOIN orders o ON o.client_id = c.client_id
GROUP BY c.client_id, c.client_name
ORDER BY c.client_id;
Результат изменился: теперь в нём 2 строки:
| client_id | client_name | total_spent |
|---|---|---|
| 1 | Анна | 3000 |
| 2 | Борис | 1500 |
Гранулярность — это то, какой именно объект описывает одна строка результата. В первом запросе гранулярность — «один заказ». Во втором запросе гранулярность — «один клиент с покупками». Из-за этого Анна попала во второй отчёт ровно один раз с суммой двух заказов 1000 + 2000 = 3000. Веры в обоих отчётах нет: INNER JOIN оставил только тех клиентов, у которых есть совпадающие строки в таблице orders.
