Merge без потерь: куда исчезают неизвестные ключи
После добавления категории выручка выросла на 7%. Формула суммы не менялась. Причина оказалась в справочнике: одному SKU соответствовали две строки.
Merge — не «подтянуть колонку». Это операция над отношением двух таблиц, и её результат зависит от уникальности ключа. До соединения ответьте на три вопроса: какая таблица задаёт состав результата, сколько строк справа допустимо для одного ключа и что делать с отсутствующим соответствием.
Профиль ключей до Merge
Продажи содержат много строк на SKU, справочник товаров — ровно одну актуальную строку на SKU. Проверим это ожидание отдельным запросом: сгруппируем справочник по SKU, посчитаем строки и оставим группы больше одной. Если список не пуст, соединение откладываем. Автоматическое удаление дублей может скрыть разные категории или цены.
Ключи также нормализуют: убирают внешние пробелы, приводят регистр, проверяют тип. Но ведущие нули удалять нельзя без договора — SKU 0017 может отличаться от 17. Нормализация должна исправлять представление, а не угадывать смысл.
Почему здесь нужен Left Outer
Главная таблица — продажи. Мы обязаны сохранить каждую продажу, даже если товар отсутствует в справочнике. Поэтому выбираем левое внешнее соединение. Inner Join отбросил бы неизвестные SKU и занизил выручку, причём итог выглядел бы аккуратно.
Merged = Table.NestedJoin(
Sales,
{"SKU"},
Products,
{"SKU"},
"Product",
JoinKind.LeftOuter
),
WithMatchCount = Table.AddColumn(
Merged,
"ProductMatches",
each Table.RowCount([Product]),
Int64.Type
),
Expanded = Table.ExpandTableColumn(
WithMatchCount,
"Product",
{"Category", "Brand"},
{"Product.Category", "Product.Brand"}
)
Столбец ProductMatches — предохранитель. Значение 0 означает отсутствующий ключ, 1 — норму, больше 1 — размножение строки. Его можно удалить из финальной витрины, но сначала строим две проверки.
Anti Join как список работы
Left Anti Join возвращает продажи, которым не нашлось товара. Группируем их по SKU, считаем количество заказов и сумму. Получается приоритизированная очередь качества данных: сначала исправляем неизвестный SKU с миллионом выручки, а не тот, который встретился один раз.
Обратный Right Anti или Left Anti от справочника к продажам показывает товары без активности. Это уже другой бизнес-вопрос и не является ошибкой соединения.
Сверяем гранулярность и сумму
До и после Merge должны совпасть количество строк продаж и общая сумма, если справа гарантирован один товар. Увеличение строк указывает на дубли справочника; уменьшение — на неверный тип соединения или фильтр. Сумма может вырасти даже при незаметном числе дублей, поэтому проверяем оба показателя.
| Строк до Merge | 48 211 |
| Строк после Merge | 48 211 |
| SKU без соответствия | 17 |
| Строк с несколькими соответствиями | 0 |
| Сумма до / после | совпадает |
Задание: намеренно продублируйте один SKU в справочнике и сравните сумму до и после Merge. Затем добавьте ProductMatches и сделайте запрос, который останавливает публикацию при значении больше единицы.
Хорошее соединение не прячет качество справочника. Оно сохраняет факты, показывает отсутствующие связи и доказывает, что детализация не изменилась.