У меня есть таблица, где у каждого человека есть записи на каждый день года. Я использовал эту функцию для получения промежуточного итога на основе столбца ежедневного баланса
CALCULATE(
SUM(Leave[Daily Balance]),
FILTER(
ALLEXCEPT(Leave, Leave[Employee Id]),
Leave[Date] <= EARLIER(Leave[Date])
))
но мне нужно, чтобы промежуточный итог перезапускался с 1, если Type = Working И промежуточный итог Daily Balance меньше нуля, а тип предыдущей строки не равен Working. Ниже приведен скриншот из Excel. Обязательный столбец функции - это то, к чему мне нужно добраться.
powerbi
dax
powerbi-desktop
LynseyC
источник
источник
Ответы:
Это не только промежуточный итог с условием, но и вложенный / кластерный, поскольку логика должна применяться на уровне идентификатора. Для больших таблиц M лучше, чем DAX, так как он не использует столько оперативной памяти. (Я писал об этом здесь: ссылка на блогпост
Следующая функция адаптирует эту логику к текущему случаю и должна применяться на уровне идентификатора: (Обязательные имена столбцов: «Тип», «Ежедневное пособие», «Корректировки»)
(MyTable as table) => let SelectJustWhatsNeeded = Table.SelectColumns(MyTable,{"Type", "Daily Allowance", "Adjustments"}), ReplaceNulls = Table.ReplaceValue(SelectJustWhatsNeeded,null,0,Replacer.ReplaceValue,{"Adjustments"}), #"Merged Columns" = Table.CombineColumns(ReplaceNulls,{"Daily Allowance", "Adjustments"}, List.Sum,"Amount"), TransformToList = List.Buffer(Table.ToRecords(#"Merged Columns")), ConditionalRunningTotal = List.Skip(List.Generate( () => [Type = TransformToList{0}[Type], Result = 0, Counter = 0], each [Counter] <= List.Count(TransformToList), each [ Result = if TransformToList{[Counter]}[Type] = "working" and [Result] < 0 and [Type] <> "working" then TransformToList{[Counter]}[Amount] else TransformToList{[Counter]}[Amount] + [Result] , Type = TransformToList{[Counter]}[Type], Counter = [Counter] + 1 ], each [Result] )), Custom1 = Table.FromColumns( Table.ToColumns(MyTable) & {ConditionalRunningTotal}, Table.ColumnNames(MyTable) & {"Result"} ) in Custom1
источник
обзор
Это сложная вещь, чтобы попросить PowerBI сделать, поэтому может быть трудно найти аккуратный подход.
Самая большая проблема заключается в том, что модель данных PowerBI не поддерживает концепцию промежуточного подсчета - по крайней мере, не так, как в Excel. В Excel столбец может ссылаться на значения, которые встречаются в «предыдущей строке» этого же столбца, а затем корректироваться с помощью некоторых «ежедневных изменений», перечисленных в другом столбце.
PowerBI может имитировать это только путем суммирования всех ежедневных изменений в некотором подмножестве строк. Мы берем значение даты в нашей текущей строке и создаем отфильтрованную таблицу, в которой все даты меньше даты текущей строки, а затем суммируем все ежедневные изменения из этого подмножества. Может показаться, что это небольшая разница, но она весьма значительна:
Это означает, что нет способа «переопределить» наш промежуточный итог. Единственная математика, которая выполняется, - это столбец, содержащий ежедневные изменения - столбец, содержащий «промежуточный итог», является только результатом - он никогда не используется в вычислениях последующих строк.
Мы должны отказаться от концепции «перезагрузки» и вместо этого представить себе создание столбца, который содержит значение «корректировки». Нашей корректировкой будет значение, которое может быть включено таким образом, чтобы при выполнении описанных условий сумма ежедневных остатков и корректировок составляла 1.
Если мы посмотрим на расчетный пробег, заданный OP, то увидим, что значение нашего промежуточного итога в «нерабочий» день непосредственно перед «рабочим» днем дает нам ту необходимую сумму, которая, если ее изменить, суммируется до нуля и вызвать увеличение промежуточного итога в каждый следующий рабочий день на единицу. Это наше желаемое поведение (с одной проблемой, которая будет описана позже).
Результат
Это помогает узнать разницу между контекстами строки и фильтра и тем, как EARLIER работает, чтобы следовать этим вычислениям. В этом сценарии вы можете думать о «РАННЕЕ» как о значении «эта ссылка указывает на значение в текущей строке», а в противном случае ссылка указывает на всю таблицу, возвращаемую «ALLEXCEPT (Leave, Leave [Id])». В этом Кстати, мы находим места, где текущая строка имеет тип «Рабочая», а строка предыдущего дня имеет какой-то другой тип.
Этот расчет имитирует операцию «заполнения». В нем говорится: «При просмотре всех строк, дата которых предшествует дате в ЭТОЙ строке, верните самое большое значение в« Самая последняя дата перед началом работы ».
Теперь, когда в каждой строке есть поле, объясняющее, куда идти, чтобы найти дневной баланс, чтобы использовать его в качестве нашей корректировки, мы можем просто посмотреть его в таблице.
И, наконец, мы применяем корректировку к нашему промежуточному итогу для конечного результата.
Проблема
При таком подходе не учитывается, что счетчик не должен сбрасываться, если текущий ежедневный баланс не станет меньше нуля. Раньше я ошибался, но я бы сказал, что этого нельзя достичь только в DAX, потому что это создает циклическую зависимость. По сути, вы предъявляете требование: используйте агрегированное значение, чтобы определить, что следует включить в агрегацию.
Так что это как далеко я могу принести вам. Надеюсь, поможет.
источник
Надеюсь, в следующий раз вы вставите CSV-код или код, который генерирует образцы данных вместо изображения. :)
Позвольте мне просто предложить вам сделать расчеты в PowerQuery. Я попытался разделить код на несколько шагов, чтобы улучшить читаемость. Это может выглядеть немного сложнее, но работает хорошо. Просто вставьте его в расширенный редактор и замените источник исходными данными. Удачи!
источник
Я думаю, что у меня есть это!
Вот результат, основанный на решении, которое я опубликовал ранее: (Данные были изменены, чтобы показать больше поведения "работа / нет работы" и варианты использования)
РЕЗУЛЬТАТ
ПОДРОБНОСТИ
(1) Отбросьте столбцы «Скорректированный текущий дневной баланс» и «Регулировка ежедневного баланса». Мы получим тот же результат с одним меньшим шагом за мгновение.
(2) Создайте следующий столбец (RDB = "текущий дневной баланс") ...
Создав «Самую последнюю дату перед завершением работы», у нас фактически есть кусок, необходимый для нашей «перезагрузки», которую, как я утверждал, раньше было невозможно. Фильтруя это поле, мы получаем возможность начинать каждый срез с «1».
(3) У нас все еще есть та же проблема, но мы не можем посмотреть на результат в нашем столбце и использовать его, чтобы решить, что делать позже в этом же столбце. Но мы МОЖЕМ построить новый столбец настроек, который будет содержать эту информацию! И у нас уже есть ссылка на «Самая последняя дата перед началом работы» - это последний день в предыдущей группе ... строка с информацией, которая нам нужна!
Поэтому мы смотрим на последний день в каждой предыдущей группе и, если общая сумма этих корректировок имеет положительное значение, мы применяем его, а если он отрицательный, мы оставляем его в покое. Кроме того, если первые несколько дней нашего сотрудника являются нерабочими днями, мы вообще не хотим, чтобы этот начальный отрицательный бит вносился в нашу настройку, поэтому он тоже отфильтровывается.
(4) Этот последний шаг приведет корректировку к окончательному результату. Суммируйте два новых столбца, и мы наконец-то получим наш скорректированный ежедневный баланс. Вуаля!
По пути к этому результату мы построили множество дополнительных столбцов, что обычно не мое любимое занятие. Но это было сложно.
источник
Прошло некоторое время, но я смог найти обходной путь. Предполагая, что значение баланса для пробелов всегда равно -1, а значение «Работает» равно 1, и эти данные доступны для всех дат без пропусков, может сработать что-то вроде приведенного ниже расчета:
Имейте в виду, это может быть не готовый продукт, так как я работал с небольшим образцом, но это должно помочь вам начать. Надеюсь это поможет.
источник
Вычисление немного длинное, но, похоже, оно работает в данных образца, которые я использую. Попробуйте это:
Я использовал кучу переменных здесь. Возможно, вы сможете придумать более короткую версию. По сути, идея состоит в том, чтобы найти предыдущее первое вхождение «Working», чтобы найти, с чего начать расчет. Это рассчитывается в переменной «Prev_Blank2». Как только мы узнаем начальную точку (здесь она начинается с 1), мы можем просто посчитать количество дней с «Working» или blank () между Prev_Blank2 и датой текущей записи. Используя эти дни, мы можем вернуть окончательное значение для промежуточного итога.
Надеюсь, это поможет;)
источник