«Многие ко многим» — частая реальность. Один товар попадает в несколько акций, а в акции участвуют много товаров. Один клиент платит с нескольких счетов, а со счёта платят несколько клиентов. Power BI умеет физическую m2m-связь напрямую, но она капризна: неоднозначные пути, сюрпризы с итогами, обязательная двунаправленность. Чище — таблица-мост.
Идея моста
Между двумя таблицами с отношением «многие ко многим» ставят третью — мост (bridge), где каждая пара встречается по одной строке. Тогда вместо одной m2m получаются две нормальные связи «один ко многим», направленные в мост:
Товары (1) ──► ТоварТег (∞) ◄── (1) Теги
[мост]
ТоварТег — это просто список пар «КодТовара ↔ Тег»: товар «Молоко» — теги «новинка», «эко»; товар «Чипсы» — тег «акция». Каждая пара уникальна. Слева мост связан с Товары, справа — с Теги, обе связи «один ко многим» со стороны моста.
Две предсказуемые связи «один ко многим» вместо одной хрупкой m2m. Мост явно виден в модели, его легко проверить и почистить от дублей. Это стандартный, надёжный приём.
Где живёт двунаправленность
Вот ключевой нюанс. По умолчанию фильтр течёт от измерения к мосту, но не дальше. Выбрали тег «акция» → отфильтровался мост → а до Товары (и до Продажи) фильтр сам не дойдёт, потому что в мост связь входит, а не выходит.
Чтобы выбор тега фильтровал продажи, нужно пропустить фильтр через мост к Товары. Два способа:
1. Двунаправленная связь — только на ребре Товары ↔ ТоварТег. Делаем эту одну связь двунаправленной (cross filter both). Теперь тег → мост → товары → продажи. Связь Теги → мост остаётся однонаправленной.
2. CROSSFILTER в мере — точечно и безопасно. Не трогаем модель, включаем сквозной фильтр только там, где нужно:
Выручка по тегу =
CALCULATE (
[Выручка],
CROSSFILTER ( Товары[КодТовара], ТоварТег[КодТовара], BOTH )
)
Глобальная двунаправленная связь — частый источник неоднозначных путей и медленных моделей. Правило: включайте «обе стороны» только на ребре между мостом и измерением, которое нужно пробросить, и предпочитайте CROSSFILTER в мере, если эффект нужен лишь в паре расчётов. Не делайте двунаправленными связи между фактом и измерениями.
Мост между двумя фактами
Тот же приём связывает две таблицы фактов на разной грануляции через общее измерение-мост. Бюджет по категории и продажи по товару связывают не напрямую, а через общий справочник (категория/товар) — он и работает мостом. Если общего справочника нет, его создают (DISTINCT/VALUES по ключу) специально как мост.
Когда мост, когда TREATAS
В прошлом уроке мы связывали таблицы виртуально через TREATAS. Когда что:
- Мост — когда связь нужна постоянно, грануляция позволяет, и важна скорость (физические связи оптимизированы движком). Это «production»-вариант для m2m.
- TREATAS — когда физическую связь сделать нельзя или она ведёт себя плохо; считается на лету, дороже на больших данных.
Мост обязан содержать уникальные пары. Дубли строк раздувают результат (выручка «задвоится»). Если строите мост из данных — гоните через DISTINCT/SUMMARIZE, а не копируйте «как есть».
Что дальше
Со связями почти закончили — физические, неактивные, виртуальные и мост. Остался выбор режима хранения: когда данные не импортируют, а оставляют в источнике. Дальше — композитные модели и DirectQuery. Следующий урок.