Мета іспиту (Model the data, 25–30 %): Use the CALCULATE function. Пов'язані: Create single aggregation measures і Identify use cases for calculated columns (u10), Implement time intelligence measures (u12), Create calculation groups (u13).
1. Біль: міра, яка має вигляд SQL і бреше
Керівниця консалтингового напряму Aldervane хоче одну матрицю: години за клієнтами, оплачувані години, частку клієнта в усіх годинах і години за клієнтами з Великої Британії. Томаш, старший розробник, який десять років пише на T-SQL, пише міри так, як написав би WHERE:
Billable Hours = CALCULATE ( [Hours], Timesheet[Billable] = "Y" )
UK Hours = CALCULATE ( [Hours], Client[Country] = "UK" )
На його першій сторінці кожне число має правильний вигляд. Потім колега перетягує Billable на рядки, а Country — на стовпці, і матриця починає показувати 28 оплачуваних годин у рядку неоплачуваних і 26 британських годин у стовпці Ireland. Нічого не зламано. Томаш прочитав CALCULATE як «додай умову». Насправді це означає «обчисли цей вираз у зміненому контексті фільтра», і зміна зазвичай замінює фільтри, а не додається до них.
Цей юніт — про цю єдину різницю. Щойно ви можете назвати контекст фільтра клітинки, кожне запитання про CALCULATE на іспиті перетворюється на арифметику.
2. Модель, яку ми рахуємо в голові
Опис
Two boxes joined by an arrow from left to right. The left box is the dimension table Client with the columns ClientName, which is the key, and Country. The right box is the fact table Timesheet with the columns ClientName, Billable with values Y or N, and Hours. The arrow is labelled one to many, single direction: a filter on Client flows to Timesheet, never the other way. All examples in this unit use this model.
Client
| ClientName | Country |
|---|---|
| Contoso Energy | UK |
| Fabrikam Logistics | Ireland |
| Woodgrove Bank | UK |
Timesheet
| ClientName | Billable | Hours |
|---|---|---|
| Contoso Energy | Y | 10 |
| Contoso Energy | N | 2 |
| Fabrikam Logistics | Y | 6 |
| Fabrikam Logistics | Y | 4 |
| Woodgrove Bank | Y | 8 |
| Woodgrove Bank | N | 6 |
Базова міра — Hours = SUM ( Timesheet[Hours] ). Підсумки, які варто тримати в голові: Contoso 12, Fabrikam 10, Woodgrove 14, усі клієнти 36; оплачувані години 28; клієнти з Великої Британії 26.
3. Контекст фільтра одним реченням (з u10)
Кожна клітинка візуального елемента обчислюється окремо. Її контекст фільтра — це набір фільтрів із заголовка рядка, заголовка стовпця, зрізів, панелі фільтрів і RLS. У матриці з ClientName на рядках клітинка Contoso має фільтр Client[ClientName] = "Contoso Energy", і цей фільтр проходить через зв'язок до Timesheet. [Hours] там дорівнює 12. Рядок підсумку не має фільтра за ClientName, тому показує 36.
Звичка для іспиту: перш ніж щось рахувати, запишіть контекст фільтра клітинки. Потім застосуйте до нього те, що робить CALCULATE.
4. CALCULATE задає фільтри — і замінює їх
CALCULATE ( <expression>, <filter1>, <filter2>, … )
Аргумент-фільтр на кшталт Timesheet[Billable] = "Y" — скорочений запис таблиці з одним стовпцем і допустимими значеннями:
-- what the engine actually uses
FILTER ( ALL ( Timesheet[Billable] ), Timesheet[Billable] = "Y" )
Зверніть увагу на ALL. Скорочений запис ігнорує будь-який фільтр, що вже існує на Timesheet[Billable], і ставить на його місце свій власний. Фільтри на інших стовпцях лишаються як є.

Опис
Two square charcoal frames on beige paper, joined by a thick arrow pointing from left to right. The left frame, labelled VISUAL, holds rows of faded coin outlines; only the top row of four slate-blue coins is solid — the selection the visual's filter lets through. The right frame, labelled CALCULATE, holds the same faded coins, but now only the bottom row of four ochre coins is solid. The idea: CALCULATE does not narrow the visual's selection further — it swaps the filter on that column for its own, so a different set of rows is counted. The picture does not show filters on other columns, which CALCULATE leaves in place.
4.1 Коли заміна — саме те, що потрібно
Матриця з ClientName на рядках:
| ClientName | Hours | Billable Hours |
|---|---|---|
| Contoso Energy | 12 | 10 |
| Fabrikam Logistics | 10 | 10 |
| Woodgrove Bank | 14 | 8 |
| Підсумок | 36 | 28 |
Фільтр рядка стоїть на ClientName, а CALCULATE фільтрує Billable. Це різні стовпці, тому два фільтри поєднуються, і числа виходять такими, яких очікував Томаш.
4.2 Коли це заскочує зненацька
Поставте на рядки натомість Timesheet[Billable]:
| Billable | Hours | Billable Hours |
|---|---|---|
| N | 8 | 28 |
| Y | 28 | 28 |
| Підсумок | 36 | 28 |
У рядку N фільтр клітинки — Billable = "N". CALCULATE замінює його на Billable = "Y", тому клітинка показує 28. Пастка іспиту: будь-яке запитання, де на осі стоїть той самий стовпець, який фільтрує міра, перевіряє, чи знаєте ви це.
Те саме відбувається з UK Hours = CALCULATE ( [Hours], Client[Country] = "UK" ):
| Вісь на рядках | Рядок | UK Hours | Чому |
|---|---|---|---|
| ClientName | Contoso Energy | 12 | фільтр ClientName лишається, додано Country = UK: Contoso — в UK |
| ClientName | Fabrikam Logistics | (порожньо) | ClientName = Fabrikam і Country = UK: таких рядків немає |
| ClientName | Woodgrove Bank | 14 | обидва фільтри виконуються |
| Country | Ireland | 26 | Country = Ireland замінено на Country = UK |
| Country | UK | 26 | замінено тим самим значенням |
Рядок Fabrikam порожній, а рядок Ireland показує 26, хоча Fabrikam — ірландський клієнт. Уся різниця в тому, який стовпець фільтрує візуальний елемент.
4.3 Перетин замість заміни: KEEPFILTERS
Якщо вимога — «години за UK, але з урахуванням того, що користувач уже вибрав», обгорніть фільтр:
UK Hours (keep) = CALCULATE ( [Hours], KEEPFILTERS ( Client[Country] = "UK" ) )
KEEPFILTERS перетинає новий фільтр з наявним на тому самому стовпці. З Country на рядках: Ireland → порожньо, UK → 26.
Табличний фільтр теж дає перетин, бо перебирає лише вже видимі рядки:
UK Hours (table) = CALCULATE ( [Hours], FILTER ( Client, Client[Country] = "UK" ) )
Це працює, але повільніше й менш точно, ніж KEEPFILTERS: фільтрується кожен стовпець Client, а не лише Country. Використовуйте FILTER, коли умові потрібне те, чого не виразити простим предикатом, — найчастіше міру (розділ 6).
5. Зняття фільтрів: частка від підсумку
Hours All Clients = CALCULATE ( [Hours], REMOVEFILTERS ( Client ) )
% of All Clients = DIVIDE ( [Hours], [Hours All Clients] )
| ClientName | Hours | Hours All Clients | % of All Clients |
|---|---|---|---|
| Contoso Energy | 12 | 36 | 33.3 % |
| Fabrikam Logistics | 10 | 36 | 27.8 % |
| Woodgrove Bank | 14 | 36 | 38.9 % |
Функції, які знімають фільтри, і коли обирати кожну:
| Функція (як аргумент CALCULATE) | Знімає | Лишає | Типове застосування |
|---|---|---|---|
REMOVEFILTERS ( Client ) |
фільтри на кожному стовпці Client | усе інше | частка від усієї фірми |
ALL ( Client ) |
те саме, що REMOVEFILTERS, коли використовується як модифікатор | усе інше | старий код; ALL також може повертати таблицю, REMOVEFILTERS — ні |
REMOVEFILTERS ( Client[ClientName] ) |
фільтр лише на одному стовпці | інші стовпці Client, наприклад Country | частка всередині країни |
ALLEXCEPT ( Client, Client[Country] ) |
усі фільтри Client, крім Country | Country | те саме, записане навпаки |
ALLSELECTED ( Client ) |
фільтри, які застосовує сам візуальний елемент | фільтри від зрізів і зовнішнього звіту | «частка від того, на що дивиться користувач» |
Пастка іспиту: «Частки мають і далі давати в сумі 100 %, коли користувач вибирає UK у зрізі» означає ALLSELECTED. З REMOVEFILTERS британські клієнти дали б у сумі лише 72 % (26 / 36), бо знаменник ігнорував би зріз.
6. Фільтрування за мірою
Булів аргумент-фільтр може порівнювати стовпці однієї таблиці з константами, але не може посилатися на міру. «Оплачувані години клієнтів, які мають загалом понад 10 годин» потребують таблиці клієнтів для перебору:
Billable Hours Big Clients =
CALCULATE (
[Billable Hours],
FILTER ( VALUES ( Client[ClientName] ), [Hours] > 10 )
)
VALUES ( Client[ClientName] ) — маленька таблиця: по одному рядку на кожного видимого клієнта. Для кожного рядка FILTER обчислює [Hours] — це міра, і тому вона спричиняє перехід контексту (наступний розділ). Перебирайте найменшу таблицю, яка відповідає на запитання, — стовпець виміру, ніколи не таблицю фактів.
7. Порядок обчислення CALCULATE
Опис
Five boxes stacked top to bottom and joined by arrows. One: the filter arguments are evaluated in the original filter context. Two: if there is a row context, context transition turns the current row into filters. Three: modifiers such as REMOVEFILTERS, ALL, USERELATIONSHIP and CROSSFILTER are applied. Four: the filter arguments are applied, replacing existing filters on the same columns, or intersecting with them when wrapped in KEEPFILTERS. Five: the expression is evaluated in the resulting filter context. The order explains why a filter argument wins over a filter that context transition created on the same column.
На іспиті порядок потрібен рідко. Він потрібен, коли два кроки торкаються того самого стовпця, наприклад аргумент-фільтр на стовпці, який також відфільтрував перехід контексту: крок 4 іде після кроку 2, тому перемагає аргумент-фільтр.
8. Перехід контексту

Опис
On the left, a column of five person pictograms stands for the rows of a table, labelled ROW; the middle person is brick red and framed. An arrow carries this one row into a black funnel. From the narrow end of the funnel an arrow enters a frame labelled FILTER, which holds nine coins in three rows: only the middle row of three brick-red coins is solid, the rest are faded. The idea: context transition turns the row being iterated into a filter, so the calculation sees only the fact rows that belong to that row. The picture does not show how many columns of the row become filters — in DAX, all of them do.
Контекст рядка існує в обчислюваних стовпцях і в ітераторах (SUMX, AVERAGEX, FILTER…). Він означає «я на цьому рядку», але нічого не фільтрує. CALCULATE його перетворює: кожен стовпець поточного рядка стає фільтром. Це перетворення і є переходом контексту.
Три обчислювані стовпці на Client:
| Обчислюваний стовпець | Contoso | Fabrikam | Woodgrove |
|---|---|---|---|
= SUM ( Timesheet[Hours] ) |
36 | 36 | 36 |
= CALCULATE ( SUM ( Timesheet[Hours] ) ) |
12 | 10 | 14 |
= [Hours] |
12 | 10 | 14 |
- Перший стовпець не має контексту фільтра, тому SUM бачить увесь Timesheet. Це класична помилка SQL-мислення: розробник очікує корельований підзапит, а отримує загальний підсумок.
- Другий стовпець використовує CALCULATE без аргументів-фільтрів. Його єдине завдання тут — перехід контексту.
- Третій посилається на міру. Посилання на міру завжди несе неявний CALCULATE, тому теж спричиняє перехід контексту.
Те саме правило діє всередині мір, які перебирають рядки:
Avg Hours per Client (right) = AVERAGEX ( Client, [Hours] ) -- total row: 12
Avg Hours per Client (wrong) = AVERAGEX ( Client, SUM ( Timesheet[Hours] ) ) -- total row: 36
У неправильній версії кожна ітерація підсумовує всі 36 годин (переходу немає), і середнє з 36, 36 і 36 дорівнює 36.
Пастка іспиту: «обчислюваний стовпець повертає одне й те саме значення в кожному рядку» вказує на відсутній перехід контексту. Виправлення — CALCULATE або посилання на міру.
9. Ціна
- FILTER по таблиці фактів працює повільно.
CALCULATE ( [Hours], FILTER ( Timesheet, Timesheet[Billable] = "Y" ) )перебирає кожен видимий рядок табеля й може бути на порядки повільнішим за предикат по стовпцю. На таблиці фактів у 10 мільйонів рядків ви побачите це в Performance Analyzer (u14). - Перехід контексту всередині великих ітераторів дорогий.
SUMX ( Timesheet, [Some Measure] )виконує перехід для кожного рядка фактів. Перебирайте натомість вимір абоVALUESстовпця. - Перехід фільтрує кожен стовпець рядка. Якщо в таблиці є рядки-дублікати, перехід фільтрує всі однакові рядки одразу. Перебір таблиці без ключа дає мовчки неправильні результати.
- Читабельність. Кожен замінений фільтр невидимий у звіті. Користувач, який бачить 28 у рядку «N», не здогадається чому. Називайте такі міри чесно (
Billable Hours (ignores Billable filter)) або використовуйтеKEEPFILTERS, якщо має перемагати фільтр візуального елемента.
| Інтуїція SQL | Що насправді робить DAX |
|---|---|
WHERE Billable = 'Y' додає умову |
фільтр CALCULATE замінює фільтр на цьому стовпці |
SUM(Hours) OVER () для загального підсумку |
CALCULATE ( [Hours], REMOVEFILTERS ( … ) ) |
| корельований підзапит на кожен рядок | обчислюваному стовпцю потрібен перехід контексту, щоб побачити «свої» рядки |
HAVING SUM(Hours) > 10 |
FILTER ( VALUES ( … ), [Hours] > 10 ) всередині CALCULATE |
10. Лабораторна — CALCULATE на датасеті Aldervane
Вам знадобляться: Power BI Desktop (безкоштовний, Windows) і публічний датасет aldervane-pbi-dataset (файли CSV плюс README зі зв'язками). Час: близько 40 хвилин. Вартість: немає.
- Get data → Text/CSV для
DimClient,DimEngagementіFactTimesheet. У Model view створітьDimClient[ClientKey] 1 → * DimEngagement[ClientKey]іDimEngagement[EngagementKey] 1 → * FactTimesheet[EngagementKey], обидва односпрямовані. - Створіть міри:
Hours = SUM ( FactTimesheet[Hours] ) Billable Hours = CALCULATE ( [Hours], FactTimesheet[Billable] = "Y" ) UK Hours = CALCULATE ( [Hours], DimClient[Country] = "UK" ) UK Hours (keep) = CALCULATE ( [Hours], KEEPFILTERS ( DimClient[Country] = "UK" ) ) Hours All Clients = CALCULATE ( [Hours], REMOVEFILTERS ( DimClient ) ) % of All Clients = DIVIDE ( [Hours], [Hours All Clients] ) - Відкрийте DAX query view і виконайте:
Очікується: Ireland 9 664 / 18 907 / порожньо; Poland 6 186 / 18 907 / порожньо; UK 18 907 / 18 907 / 18 907. Поясніть кожне число вголос, перш ніж дивитися.EVALUATE SUMMARIZECOLUMNS ( DimClient[Country], "Hours", [Hours], "UK Hours", [UK Hours], "UK Hours (keep)", [UK Hours (keep)] ) - Побудуйте матрицю з
DimClient[ClientName]на рядках і[Hours],[% of All Clients]. Contoso Energy має показати 19.5 %. Додайте зріз заCountry, виберіть UK і подивіться, як частки перестають давати в сумі 100 %. Змініть знаменник наALLSELECTED ( DimClient )і перевірте знову. - На
DimEngagementдодайте два обчислювані стовпці:Hours (bare) = SUM ( FactTimesheet[Hours] )іHours (CT) = [Hours]. Для ENG-4401 очікуйте 34 757 і 1 567.5. - Загальний підсумок — 34 757 годин як завантажено: ця лабораторна завантажує CSV наново, тому навмисний запис на −3 години досі всередині. Очищення в u04 його видаляє (після нього 34 760 годин); числа лабораторної вище — як завантажено.
Немає машини з Windows або Desktop заблоковано? Пройдіть кроки 2–5 на папері, використовуючи очікувані числа вище. Будь-яке практичне завдання цього юніта можна розв'язати без Power BI.
11. Пастки іспиту — підсумок
- Аргумент-фільтр замінює фільтр на тому самому стовпці; інші стовпці зберігають свої фільтри.
- Той самий стовпець на осі й в аргументі-фільтрі → кожен рядок показує одне й те саме число.
- «З урахуванням вибору користувача» →
KEEPFILTERS(або табличний фільтр). - «Частка від усього» →
REMOVEFILTERS/ALL; «частка від вибраного» →ALLSELECTED; «частка всередині країни» → зняти лише фільтр ClientName /ALLEXCEPT. - Булів фільтр не може використовувати міру →
FILTER ( VALUES ( … ), [Measure] > x ). - Обчислюваний стовпець показує загальний підсумок у кожному рядку → бракує переходу контексту; використовуйте CALCULATE або посилання на міру.
- Посилання на міру = неявний CALCULATE.
12. Запам'ятайте картинки
Перекажіть кожну картинку одним реченням. Дві рамки: CALCULATE підміняє фільтр на стовпці, а не звужує його. Лійка: поточний рядок стає фільтром. Якщо ви можете сказати обидва, не дивлячись, у вас у руках суть цієї мети іспиту.
Джерела: Microsoft Learn — "CALCULATE function (DAX)", "KEEPFILTERS function (DAX)", "ALLSELECTED function (DAX)", "Modify DAX filter context in semantic models" (training module, unit "Perform context transition"), "DAX query view". Exam PL-300 study guide, skills measured as of April 20, 2026.
