Огляд
Попросити PowerBI це складна річ, тому охайний підхід може бути важко знайти.
Найбільша проблема полягає в тому, що модель даних PowerBI не підтримує концепцію функціонування, принаймні, не так, як ми це робимо в Excel. У Excel, стовпець може посилатись на значення, які зустрічаються у "попередньому рядку" того самого стовпця, а потім коригуватись деякою "щоденною зміною", вказаною в іншому стовпці.
PowerBI може наслідувати це лише шляхом додавання всіх щоденних змін протягом деякого підмножини рядків. Ми беремо значення дати в нашому поточному рядку і створюємо відфільтровану таблицю, де всі дати менші за дату поточного рядка, а потім підсумовуємо всі щоденні зміни з цього підмножини. Це може здатися незначною різницею, але вона досить значна:
Це означає, що немає способу "переоцінити" наш підсумковий результат. Єдина математика, що робиться, відбувається на стовпчику, що містить щоденні зміни - стовпець, що містить "загальну кількість", є лише результатом - він ніколи не використовується в обчисленні наступних рядків.
Ми повинні відмовитися від концепції "скидання" і замість цього уявити собі стовпець, який містить значення "коригування". Наше коригування буде значенням, яке може бути включено таким чином, що при дотриманні описаних умов загальна сума щоденних залишків та коригувань складе 1.
Якщо ми подивимось на розрахунковий показник, заданий ОП, то побачимо, що значення нашої загальної суми за «неробочий» день безпосередньо перед «робочим» днем дає нам необхідну суму, яка, якщо буде зворотна, складе нуль і зробіть загальний обсяг кожного наступного робочого дня на одиницю. Це наша бажана поведінка (одна проблема буде описана далі).
Результат
Most Recent Date Prior to Work =
CALCULATE(
Max(Leave[Date]),
FILTER(
ALLEXCEPT(Leave, Leave[Id]),
Leave[Date] = EARLIER(Leave[Date]) -1 && Leave[Type] <> "Working" && Earlier(Leave[Type]) = "Working"
))
Це допомагає дізнатися різницю між контекстами рядків та фільтрів та тим, як EARLIER працює для цього розрахунку. У цьому сценарії ви можете вважати "EARLIER" як сенс "ця опорна точка на значення в поточному рядку", а в іншому випадку - опорну точку на всю таблицю, повернуту "ALLEXCEPT (Leave, Leave [Id])". Таким чином, ми знаходимо місця, де поточний рядок має тип "Робочий", а рядок попереднього дня має якийсь інший тип.
Most Recent Date Prior to Work Complete =
CALCULATE(
Max(Leave[Most Recent Date Prior to Work]),
FILTER(
ALLEXCEPT(Leave, Leave[Id]),
Leave[Date] <= EARLIER(Leave[Date])
))
Цей розрахунок імітує операцію "заповнення". У ній написано: "Переглядаючи всі рядки, дата яких є перед датою в ЦЬОМУ ряду, поверніть найбільше значення у" Найновіша дата до початку роботи ".
Daily Balance Adjustment =
CALCULATE(
SUM(Leave[Running Daily Balance]),
FILTER(
ALLEXCEPT(Leave, Leave[Id]),
Leave[Date] = EARLIER(Leave[Most Recent Date Prior to Work Complete])
))
Тепер, коли в кожному рядку є поле, в якому пояснюється, куди звернутися, щоб знайти щоденний баланс, який слід використовувати як наше коригування, ми можемо просто переглянути його з таблиці.
Adjusted Daily Balance = Leave[Running Daily Balance] - Leave[Daily Balance Adjustment]
І, нарешті, ми застосовуємо коригування до нашої загальної суми для остаточного результату.
Питання
Цей підхід не дозволяє вирішити, що підрахунок не повинен скидатися, якщо поточний щоденний баланс не перевищує нуля. Мені раніше було доведено неправильно, але я б сказав, що цього неможливо зробити лише в DAX, оскільки це створює кругову залежність. По суті, ви пред'являєте вимогу: використовуйте зведене значення, щоб визначити, що слід включати в агрегацію.
Так що я можу вас довести. Сподіваюся, це допомагає.