SUM после JOIN врёт: дубли строк

Соединяете заказы с позициями в заказе — обычное дело, обычный JOIN.

SELECT o.id, SUM(o.total) AS выручка
FROM invoices o
JOIN invoice_items i ON i.invoice_id = o.id
GROUP BY o.id;

Заказ на сто долларов с пятью позициями внутри вдруг стоит пятьсот. Никто ничего не украл — заказ просто размножился по числу своих же позиций.

«Один заказ, пять строк-детей — и JOIN честно повторил родителя пять раз. Плодятся не деньги. Плодятся строки.»

Поможет ли здесь DISTINCT?

Первый порыв — прилепить DISTINCT сверху. Не поможет: DISTINCT прячет одинаковые строки-результаты, а тут строки-то как раз разные (разные позиции внутри заказа) — маскировка симптома, не лечение причины.

Лечение — свернуть таблицу с детьми до нужной зернистости ДО соединения, а уже потом присоединять к родителю.

WITH позиций_на_заказ AS (
  SELECT invoice_id, COUNT(*) AS n
  FROM invoice_items GROUP BY invoice_id
)
SELECT o.id, o.total
FROM invoices o
JOIN позиций_на_заказ n ON n.invoice_id = o.id;
-- сумма считается по родителю ДО умножения детьми
«Проверка на всякий случай: посчитайте строки до JOIN и после. Стало больше, чем было в исходной таблице, — где-то родитель расплодился.»

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

Сумма, которая соврала, — не редкость и не экзотика. В архиве есть дело, где она врёт с первой же строки.

$0
тащи карточки за верхнюю кромку · «+ стикер» · «🧵 нить» — клик по двум

ЛОТОК УЛИК

во вкладке SQL найди подозреваемых и жми «+ доска»

НА ПРОВЕРКУ

теории из «Заметок» отправляются сюда — подтверди на доске или удали
Ctrl+Enter · «+ доска» на строке — выбрать поля и перенестипиши запрос, я подожду
Результат появится здесь.

Картотека

Заметки

Факты

Теории на проверку

Подсказки

◆ РЕЖИМ АРХИВАРИУСАуправление картотекой дел · не виден игроку