DAX для початківців: міри, CALCULATE та контекст
Ви побудували модель даних, налаштували зв’язки — і вперлися в стелю. Стандартні агрегати Power BI показують суму чи кількість, але не вміють порахувати «продажі за цей рік порівняно з минулим» або «частку міста в загальній виручці». Для таких розрахунків потрібен DAX (Data Analysis Expressions) — мова формул Power BI.

DAX лякає новачків не синтаксисом, а поняттям контексту: одна й та сама міра повертає різні числа в різних клітинках візуала. Щойно ви зрозумієте, як працює контекст фільтра, 80% «магії» DAX стане передбачуваною логікою.
Це урок 8 безкоштовного курсу аналітики даних. Ми розберемо різницю між колонками та мірами, функції SUM і SUMX, головну функцію CALCULATE та базовий time intelligence — усе на знайомій моделі магазину з таблицями orders, customers, products і order_items.
Що таке DAX і навіщо він потрібен
DAX — це мова формул для Power BI, Power Pivot в Excel та Analysis Services. Зовні вона схожа на формули Excel: є функції, дужки, оператори. Але принципова різниця в тому, що DAX працює не з окремими клітинками, а з колонками й таблицями цілком.
У Power BI DAX використовують для трьох речей: обчислюваних колонок, мір і обчислюваних таблиць. У цьому уроці зосередимося на перших двох — саме вони потрібні в 95% реальних звітів.
Важливий нюанс: коли ви просто перетягуєте числову колонку у візуал, Power BI створює неявну міру (автоматичний SUM або COUNT). Для навчальних звітів це прийнятно, але в робочих моделях краще писати явні міри: їх можна перевикористовувати, форматувати й посилатися на них в інших формулах.
Обчислювані колонки vs міри
Це перший вибір, який ви робите перед написанням формули. Обчислювана колонка додає нове значення в кожен рядок таблиці й зберігається в моделі. Міра нічого не зберігає — вона обчислюється «на льоту» в момент, коли ви кладете її у візуал.
| Критерій | Обчислювана колонка | Міра |
|---|---|---|
| Коли обчислюється | Під час оновлення даних | Під час взаємодії зі звітом |
| Де зберігається | У моделі, займає пам’ять | Не зберігається |
| Контекст за замовчуванням | Контекст рядка | Контекст фільтра |
| Типове використання | Категорія, прапорець, ключ для зв’язку | Суми, середні, частки, порівняння періодів |
| Вплив на розмір файлу | Збільшує | Майже не впливає |
Практичне правило: якщо результат потрібен для агрегації у візуалі — пишіть міру. Колонку створюйте лише тоді, коли значення потрібне як вісь, зріз або умова на рівні рядка. Приклад корисної колонки — рік замовлення:
Рік замовлення = YEAR(orders[order_date])А ось сума продажів має бути мірою, а не колонкою:
Сума продажів = SUM(orders[amount])Контекст: чому одна міра дає різні числа
Контекст — це набір умов, за яких обчислюється формула. У DAX є два типи контексту, і їх плутання — джерело більшості помилок початківців.
Контекст рядка
Контекст рядка означає «формула бачить один поточний рядок таблиці». Він автоматично існує в обчислюваних колонках: коли ви пишете YEAR(orders[order_date]), Power BI проходить рядок за рядком і для кожного бере його власну дату. У мірах контексту рядка за замовчуванням немає — його створюють функції-ітератори, як-от SUMX.
Контекст фільтра
Контекст фільтра — це всі фільтри, що діють на клітинку візуала: значення на осях, зрізи, фільтри сторінки, виділення в сусідніх діаграмах. Якщо міра «Сума продажів» стоїть у рядку «Київ» таблиці за містами, Power BI спершу відфільтрує замовлення клієнтів із Києва, а вже потім підсумує amount.
Саме тому та сама міра показує 50 000 у рядку «Київ», 30 000 у рядку «Львів» і 200 000 у підсумку. Формула одна — контекст фільтра різний. Коли міра повертає «дивне» число, перше питання завжди однакове: які фільтри діють на цю клітинку?
SUM і SUMX: агрегати та ітератори
SUM просто підсумовує одну колонку в поточному контексті фільтра. Але що робити, коли потрібно спершу перемножити значення в кожному рядку? У таблиці order_items є кількість qty, а ціна лежить у пов’язаній таблиці products. Написати SUM(order_items[qty] * products[price]) не вийде — SUM приймає лише одну колонку.
Тут потрібен ітератор SUMX. Він проходить таблицю рядок за рядком (створює контекст рядка), обчислює вираз для кожного рядка і підсумовує результати:
Виручка за позиціями =
SUMX(
order_items,
order_items[qty] * RELATED(products[price])
)Функція RELATED підтягує ціну з таблиці products через зв’язок, який ви налаштували в уроці про моделювання. Аналогічно працюють AVERAGEX, MINX, MAXX і COUNTX — усі вони ітератори з тим самим принципом «таблиця + вираз».
CALCULATE — головна функція DAX
CALCULATE обчислює вираз у зміненому контексті фільтра. Це єдина функція, яка вміє переписувати фільтри, тому її називають серцем DAX. Синтаксис простий: перший аргумент — вираз (зазвичай міра), далі — один або кілька фільтрів.
Продажі завершені =
CALCULATE(
[Сума продажів],
orders[status] = "completed"
)Ця міра завжди рахує тільки завершені замовлення — незалежно від того, у якому візуалі стоїть. Фільтр orders[status] = "completed" додається до наявного контексту, а якщо у контексті вже був інший фільтр по status, він замінюється новим.
CALCULATE + FILTER для складних умов
Простий фільтр у CALCULATE порівнює колонку з константою. Коли умова складніша — наприклад, порівняння з мірою або кілька колонок в одній умові — використовуйте FILTER:
Продажі великих замовлень =
CALCULATE(
[Сума продажів],
FILTER(
orders,
orders[amount] > 1000 && orders[status] = "completed"
)
)FILTER повертає відфільтровану таблицю, яку CALCULATE застосовує як фільтр. Майте на увазі: FILTER — ітератор, і на великих таблицях він працює повільніше за простий фільтр-предикат. Якщо умову можна записати без FILTER — запишіть без нього.
ALL: знімаємо фільтри й рахуємо частки
Функція ALL робить протилежне — прибирає фільтри з таблиці або колонки. Класичне застосування — відсоток від загального. У таблиці за містами кожен рядок фільтрує продажі свого міста, а для частки потрібен ще й загальний підсумок без цього фільтра:
% від усіх міст =
DIVIDE(
[Сума продажів],
CALCULATE([Сума продажів], ALL(customers[city]))
)Чисельник рахується у поточному контексті (одне місто), а знаменник — у контексті, де фільтр по місту знято. DIVIDE замість оператора «/» захищає від ділення на нуль. Споріднені функції: ALLSELECTED (враховує зрізи, але ігнорує осі візуала) та ALLEXCEPT (знімає всі фільтри, крім указаних).
Time intelligence: порівнюємо періоди
Функції часового аналізу — головна причина, чому в моделі потрібна календарна таблиця (ми створювали її в попередньому уроці). Вони працюють коректно, лише коли отримують безперервну колонку дат, позначену як таблиця дат.
Дві найуживаніші функції. TOTALYTD накопичує значення з початку року до поточної дати контексту:
Продажі YTD =
TOTALYTD([Сума продажів], 'Календар'[Date])SAMEPERIODLASTYEAR зсуває контекст дат на рік назад — так порівнюють період із аналогічним торік:
Продажі рік тому =
CALCULATE(
[Сума продажів],
SAMEPERIODLASTYEAR('Календар'[Date])
)
Приріст рік до року % =
DIVIDE(
[Сума продажів] - [Продажі рік тому],
[Продажі рік тому]
)Зверніть увагу: міри посилаються на інші міри. Це нормальна практика — будуйте прості «базові» міри, а складні збирайте з них, як із цеглинок. Так формули легше читати й виправляти.
Коли освоїте ці дві функції, погляньте на споріднені: DATESYTD, PREVIOUSMONTH, DATEADD і DATESINPERIOD для ковзних періодів. Усі вони працюють за тим самим принципом — повертають набір дат, який CALCULATE підставляє в контекст фільтра замість поточного.
Поширені помилки
- Колонка замість міри. Обчислювані колонки для сум і часток роздувають модель і не реагують на фільтри так, як ви очікуєте. Агрегати — завжди мірами.
- SUM там, де потрібен SUMX. Якщо перед підсумовуванням треба щось перемножити чи обчислити в кожному рядку — це робота ітератора, а не простого SUM.
- Time intelligence без календарної таблиці. TOTALYTD і SAMEPERIODLASTYEAR по колонці
orders[order_date]з пропусками дат дають неправильні результати. Створіть календар і позначте його як таблицю дат. - FILTER по всій таблиці без потреби.
FILTER(orders, orders[status] = "completed")повільніший за простий предикатorders[status] = "completed". FILTER лишайте для умов, які інакше не записати. - Забутий DIVIDE. Оператор «/» падає з помилкою або показує «нескінченність» при діленні на нуль. DIVIDE повертає порожнє значення або заданий вами запасний результат.
- Ігнорування контексту. Якщо міра показує однакове число в усіх рядках — найчастіше ви зняли фільтр через ALL там, де не треба, або фільтруєте не ту таблицю.
FAQ
Чим DAX відрізняється від формул Excel?
Синтаксис схожий, але Excel працює з клітинками та діапазонами, а DAX — з колонками й таблицями. У DAX немає поняття «клітинка A1»: результат завжди залежить від контексту фільтра, тобто від того, де саме у звіті стоїть формула.
Чи потрібно вчити всі функції DAX?
Ні. Для впевненого старту досить SUM, SUMX, CALCULATE, FILTER, ALL, DIVIDE, RELATED і двох-трьох функцій time intelligence. Це покриває більшість задач бізнес-звітності. Решту функцій ви додаватимете поступово, коли з’являться конкретні задачі.
Де зберігати міри, щоб не загубитися?
Створіть порожню таблицю (наприклад, через «Введення даних»), назвіть її «_Міри» й переносьте туди всі міри. Так вони лежатимуть в одному місці на панелі полів, а не будуть розкидані по таблицях фактів і вимірів.
Чому моя міра повертає порожнє значення?
Найчастіші причини: контекст фільтра відсіяв усі рядки (наприклад, комбінація зрізів без даних), розірваний зв’язок між таблицями або фільтр у CALCULATE, який суперечить наявному контексту. Перевірте зв’язки в поданні моделі й тимчасово приберіть фільтри з візуала.
Що далі
Ви освоїли фундамент DAX: тепер ви знаєте, коли писати колонку, а коли міру, як CALCULATE змінює контекст фільтра і як порівнювати періоди через time intelligence. Потренуйтеся: створіть у своїй моделі магазину міри «Виручка», «% від загального» та «Приріст рік до року» і покладіть їх на дашборд.
Якщо міри повертають дивні числа — проблема майже завжди в моделі, тож поверніться до попереднього уроку «Моделювання даних у Power BI: зв’язки та схема “зірка”» і перевірте зв’язки та календарну таблицю.
А в наступному, фінальному уроці зберемо все докупи: «Як стати дата-аналітиком з нуля: покроковий план» — навички, портфоліо та план навчання на 90 днів. Повний перелік уроків — на сторінці курсу аналітики даних.
Це урок 8 з 9 курсу аналітики даних.
Уроки виходять щодня о 09:30 — програма і навігація на сторінці курсу.