Выручка удвоилась после join заказов к таблице shipments «один-ко-многим». Найдите и исправьте.
Итоговая выручка была верной, пока этот отчёт не соединил orders с shipments (у одного заказа может быть много отгрузок). Теперь total вдвое больше реального.
SELECT o.region, SUM(o.amount) AS total
FROM orders o
JOIN shipments s ON s.order_id = o.order_id
GROUP BY o.region;
Объясните причину и почините агрегат, чтобы выручка была верной.
Join к shipments «один-ко-многим» повторяет строку заказа на каждую отгрузку, поэтому SUM(o.amount) складывает сумму заказа много раз — fan-out. Сверните shipments в строку на заказ (CTE), затем join, либо SUM лишь по столбцу уровня отгрузки.
- ✗Суммировать родительский столбец через join один-ко-многим
- ✗Винить cross join вместо законного fan-out
- ✗Пытаться усреднением убрать дублированные строки
- →Как COUNT(DISTINCT o.order_id) помогает найти fan-out?
- →Когда пред-агрегация shipments лучше, чем SUM(DISTINCT)?
Each order with N shipments becomes N rows after the join, so SUM(o.amount) adds that order's amount N times. With most orders shipped twice, the total roughly doubles. This is join fan-out — a real duplication, not a wrong keyword.
Collapse the child table to one row per order before joining (or skip the join entirely if you only need order-level revenue):
SELECT o.region, SUM(o.amount) AS total
FROM orders o
JOIN (
SELECT order_id
FROM shipments
GROUP BY order_id -- one row per order
) s ON s.order_id = o.order_id
GROUP BY o.region;
If you must keep the row expansion (e.g. you also report a shipment metric), count the parent value once with SUM(o.amount) FILTER (WHERE s.shipment_seq = 1) or use COUNT(DISTINCT o.order_id) to verify no order is double-counted.