Короткий ответ
Скорее всего, таблица цен хранит несколько исторических строк на один product_id (разные периоды действия цены), и JOIN по одному только product_id без условия на дату заказа размножает строки заказа на количество версий цены (fan-out); исправление — добавить условие по дате в JOIN, выбирающее ровно одну актуальную на момент заказа запись.
Как это работает подробнее
Если dim_product_price_history имеет грануляцию «одна строка на период действия цены товара» (несколько строк на product_id), а JOIN сделан только по product_id без учёта valid_from/valid_to, то каждая строка fact_orders размножается на число совпавших версий цены.
Пример кода
example.sql
SELECT o.order_id, o.amount, p.price
FROM fact_orders o
JOIN dim_product_price_history p
ON o.product_id = p.product_id
AND o.order_date BETWEEN p.valid_from AND COALESCE(p.valid_to, DATE '9999-12-31');Что использовать на практике
- На практике. Правильный JOIN должен включать условие order_date BETWEEN valid_from AND COALESCE(valid_to, 'infinity') — это гарантирует ровно одну совпавшую строку цены на каждый заказ, если периоды действия цен не пересекаются.
- Проверка. COUNT(*) результата JOIN должен быть равен COUNT(*) исходной fact_orders (каждому заказу соответствует ровно одна строка цены); если больше — значит периоды действия цены пересекаются и нужно разбираться с качеством dim_product_price_history.
Подводные камни
- Частые ошибки. Джойнят по «последнему» или «любому» совпадению без учёта исторических версий, полагая, что таблица цен содержит только текущие значения; либо после обнаружения задвоения «решают» проблему через DISTINCT, что маскирует симптом, но не устраняет источник некорректного JOIN и может случайно выкинуть легитимные разные заказы.