S
Supanote
Sign in Sign up

Сумма после JOIN выросла: маленький SQL-тест перед большим отчётом

markdown 10 hours ago · 72 lines · 4 views

Сумма после JOIN выросла: маленький SQL-тест перед большим отчётом

В таблице заказов три покупки, в таблице позиций четыре строки. После объединения заказов с позициями сумма выручки неожиданно выросла. Запрос выполняется без ошибки, результат выглядит аккуратно, а число неверное. Такой пример полезен для первых занятий SQL: он заставляет смотреть на смысл строки, а не только на правильность синтаксиса.

Задать смысл каждой таблицы

В этом учебном примере одна строка orders означает один заказ. Поле total хранит сумму всего заказа. Одна строка items означает одну позицию внутри заказа. Это разные уровни детализации. Если у заказа две позиции, объединение повторит его сумму в двух строках.

Создайте небольшой набор искусственных данных. Здесь нет покупателей, телефонов или других личных сведений.

CREATE TABLE orders (id INTEGER PRIMARY KEY, total INTEGER);
CREATE TABLE items (order_id INTEGER, product TEXT);
INSERT INTO orders VALUES (1, 100), (2, 200), (3, 300);
INSERT INTO items VALUES
  (1, 'карандаш'), (1, 'тетрадь'),
  (2, 'альбом'), (3, 'папка');

До написания отчёта посчитайте контрольную сумму вручную: 100 + 200 + 300 = 600. Именно такой результат должен получиться для выручки всех трёх заказов.

Увидеть лишнее повторение

Выполните запрос без агрегирования:

SELECT o.id, o.total, i.product
FROM orders AS o
JOIN items AS i ON i.order_id = o.id
ORDER BY o.id, i.product;

Он возвращает четыре строки. Заказ номер один появляется дважды, потому что содержит два товара. Это нормальное поведение объединения. Ошибка возникает, если следующей операцией сложить повторённое поле total и назвать результат выручкой.

SELECT SUM(o.total)
FROM orders AS o
JOIN items AS i ON i.order_id = o.id;

Результат будет 700. Запрос не знает, что повторять сумму заказа для этой задачи нельзя. Ответственность за уровень расчёта остаётся у человека, который формулирует отчёт.

Выбрать исправление по задаче

Если нужны суммы всех заказов, таблица позиций здесь вообще не требуется:

SELECT SUM(total) FROM orders;

Если нужны только заказы, у которых есть хотя бы одна позиция, проверяйте наличие, сохраняя одну строку на заказ:

SELECT SUM(o.total)
FROM orders AS o
WHERE EXISTS (
  SELECT 1 FROM items AS i WHERE i.order_id = o.id
);

Оба исправленных запроса на этом наборе дают 600. Они не равнозначны на любых данных: добавленный заказ без позиций войдёт в первый расчёт и не войдёт во второй. Выбор зависит от определения показателя.

Не заменяйте решение на SUM(DISTINCT total). Если два разных заказа стоят одинаково, такая сумма посчитает их стоимость только один раз. Уникальным должен быть идентификатор заказа, а не денежное значение.

Превратить пример в проверку учебной программы

Попросите показать, как на курсе разбирают похожую ошибку. Достаточно ли просто получить ожидаемое число, или студент объясняет, почему запрос его возвращает? Есть ли задания с несколькими товарами, одинаковыми суммами заказов и отсутствующими позициями? Эти случаи помогают отличить понимание от запоминания шаблона.

Для сравнения направлений обучения пригодится подборка курсов по SQL и работе с таблицами на KGAM. Конкретную программу стоит проверять по самостоятельным заданиям и разбору неверных результатов, а не по одному списку команд в описании.

Перед использованием запроса в настоящем отчёте запишите три вещи: что означает строка исходной таблицы, что означает строка после объединения и какой объект должен учитываться один раз. Затем добавьте маленький контрольный набор с заранее известным ответом. Такая проверка не заменяет проверку всей системы, но делает одну распространённую ошибку заметной до встречи с большим массивом данных.

No replies yet

Every reply is a note. Start a discussion, ask a question, or attach a code snippet.

Share Note

Download SVG
Social Card Preview
Open on mobile
Point your phone camera to open this note directly

Report this note

Notification