Урок 28 · 9 мин чтения

Конвертация валют

Свести продажи в разных валютах к одной отчётной по курсам на дату — без отдельных мер на каждую валюту.

Компания продаёт в рублях, долларах и юанях, а отчёт нужен в одной валюте. Соблазн — завести [Выручка USD], [Выручка EUR]… — не масштабируется. Правильно: одна мера + таблица курсов. Разбираем по DAX Patterns SQLBI.

На каком примере

В учебном наборе одна валюта. Поэтому пример на расширенной схеме: Продажи[Валюта, Сумма], справочник Курсы[Дата, Валюта, Курс] (курс к отчётной валюте), и Календарь.

Две модели курсов

Сначала решите, как часто меняется курс:

  • Дневные курсы — курс на каждый день. Точнее, тяжелее. Конвертируем каждую продажу по курсу её дня.
  • Месячные курсы — один курс на месяц (например, средний). Проще и часто достаточно для управленческой отчётности.

От этого зависит грануляция связи Курсы с Календарём.

Базовый паттерн — построчно

Главный приём: конвертируем на уровне строки факта, потом суммируем. Курс берём по дате и валюте каждой продажи:

Выручка в отчётной валюте =
SUMX (
    Продажи,
    VAR _Курс =
        LOOKUPVALUE (
            Курсы[Курс],
            Курсы[Дата], Продажи[Дата],
            Курсы[Валюта], Продажи[Валюта]
        )
    RETURN
        Продажи[Сумма] * _Курс
)

SUMX идёт по продажам, для каждой LOOKUPVALUE достаёт курс на её дату и валюту, умножает и складывает. Это семейство итераторов (урок про X-функции) в чистом виде.

Почему построчно

Нельзя сконвертировать «итог» — у разных строк разные валюты и даты. Конвертация делается на самом детальном уровне (строка продажи), и только потом суммируется. Это ключевая идея валютного паттерна.

Через связь и USERELATIONSHIP

Если Курсы связаны с Календарём и со справочником валют, вместо LOOKUPVALUE используют связи и RELATED/USERELATIONSHIP (уроки про связи). Это быстрее на больших фактах, чем LOOKUPVALUE в каждой строке, но требует аккуратной модели курсов.

Пропущенные курсы

Курса ровно на дату продажи может не быть (выходной, праздник). Стандартное решение — брать последний доступный курс на дату ≤ даты продажи:

VAR _Курс =
    CALCULATE (
        LASTNONBLANKVALUE ( Курсы[Дата], MAX ( Курсы[Курс] ) ),
        Курсы[Дата] <= Продажи[Дата],
        Курсы[Валюта] = Продажи[Валюта]
    )

Это та же логика «последнего значения», что в semi-additive остатках.

Не плодите меры на валюту

[Выручка USD], [Выручка EUR], [Выручка CNY] — антипаттерн: не масштабируется, дублирует логику, ломается на новой валюте. Одна мера + таблица курсов + (опционально) выбор отчётной валюты параметром (урок про what-if) закрывают любое число валют.

Выбор отчётной валюты пользователем

Отчётную валюту можно сделать параметром: пользователь выбирает «в чём смотреть», а мера берёт курсы к этой валюте. Это disconnected-параметр + SELECTEDVALUE (урок про what-if), наложенный на паттерн выше.

Что дальше

Валютный паттерн — последний в блоке DAX-паттернов. Дальше — экспертный курс «Эксплуатация и масштаб»: RLS, инкрементальное обновление, оптимизация, модели на SSAS. Курс пополняется.

Как правильно свести продажи в разных валютах к одной отчётной?
Конвертация делается на уровне строки факта (у строк разные валюты/даты), затем суммируется — это SUMX + поиск курса по дате и валюте. Отдельные меры на каждую валюту не масштабируются; одна мера + таблица курсов закрывает любое их число.
Прогресс сохраняется в вашем браузере.
§ Power BI под ключ

Нужно внедрить
это в компании?

Соберём DWH, модель и дашборды под ваши данные. Бесплатная консультация — 30 минут.

Телефон+7 918 042 34 43