Вопрос возник в результате попытки осмысления решения, предложенного на задачу участника под ником stanislove. Надеюсь, он не обидится на меня, если я сошлюсь на его задачу и предложенное решение в данной теме.
Собственно, к вопросу. Пользовательская функция достаточно сложная. Очевидно её нужно отлаживать. Во избежание...
Вопрос: но как? Какие механизмы? Есть ли способ пройти пользовательскую функцию по шагам, чтобы посмотреть, как отрабатывает каждый оператор, входящий в функцию? А то в окне "примененные шаги" вся функция, совместно с оператором вызова - это всё один большой шаг...
let
myfunc = (a, b) =>
let
c = a + b
in
c,
result = myfunc(5, 6)
in
result
Что мы делаем, когда используем функцию? Передаём ей некоторые значения. Тогда чтобы отладить преобразуем функцию в запрос, где её аргументы будут иметь некоторые значения.
Код
let
// указываем значения аргументов
a = 5,
b = 6,
// собственно сами шаги функции
c = a + b
in
c
Основная задача - это для анонимных функций, как в приведённой вами, знать что будет на входе, чтобы правильно задать значения аргументов. В Table.Group аргументом для (sub) => является подтаблица, в которой значения списка столбцов группировки - одинаковые. Тогда создаём вспомогательную таблицу и используем её в качестве такого значения аргумента. В примере запрос - Отладка функции. Плюс, это файл, предложенный АБСАБС, в котором он предложил, чуть другой подход.
Для группировки я обычно делаю так: создаю сначала группировку "Все строки":
Код
calc = Table.Group(Source, {"Источник (кто)"}, {"temp", each _, type table})
затем тыкаю в самую характерную из получившихся вложенных таблиц (например, тыкаем в первую). Получаем шаг типа
Код
#"Expanded{0}" = calc{0}[temp]
переименовываю его, например, в sub. Дальше делаю нужные преобразования:
Код
setOrder = Table.Sort(sub, {"Дата вызова", "Время начала разговора"}),
addInfo = Table.AddColumn(setOrder, "temp", each
[start = [Дата вызова] + Duration.From([Время начала разговора]),
finish = start + #duration(0, 0, 0, [#"Продолжительность разговора (сек)"])
]),
baseData = Table.ExpandRecordColumn(addInfo[[temp]], "temp", {"start", "finish"}),
before = Table.ToColumns(Table.RemoveLastN(baseData, 1)),
after = Table.ToColumns(Table.RemoveFirstN(baseData, 1)),
result = Table.FromColumns(before & after),
oneMoreResult = Table.AddColumn(result, "Column5", each Duration.TotalSeconds([Column3] - [Column2]))
in
oneMoreResult
В общем, делаю то, что должна делать функция. В итоге у меня получается вот такой код:
Код
calc = Table.Group(Source, {"Источник (кто)"}, {"temp", each _, type table}),
sub = calc{0}[temp],
setOrder = Table.Sort(sub, {"Дата вызова", "Время начала разговора"}),
addInfo = Table.AddColumn(setOrder, "temp", each
[start = [Дата вызова] + Duration.From([Время начала разговора]),
finish = start + #duration(0, 0, 0, [#"Продолжительность разговора (сек)"])
]),
baseData = Table.ExpandRecordColumn(addInfo[[temp]], "temp", {"start", "finish"}),
before = Table.ToColumns(Table.RemoveLastN(baseData, 1)),
after = Table.ToColumns(Table.RemoveFirstN(baseData, 1)),
result = Table.FromColumns(before & after),
oneMoreResult = Table.AddColumn(result, "Column5", each Duration.TotalSeconds([Column3] - [Column2]))
in
oneMoreResult
все, что нужно теперь сделать, это в расширенном редакторе чуть-чуть почистить, заменив функцию "each _" на "(sub)=>" и добавив let/in для вложенных в функцию шагов, и еще один in в конце, вот так:
Код
calc = Table.Group(Source, {"Источник (кто)"}, {"temp", (sub)=>
// sub = calc{0}[temp],
let
setOrder = Table.Sort(sub, {"Дата вызова", "Время начала разговора"}),
addInfo = Table.AddColumn(setOrder, "temp", each
[start = [Дата вызова] + Duration.From([Время начала разговора]),
finish = start + #duration(0, 0, 0, [#"Продолжительность разговора (сек)"])
]),
baseData = Table.ExpandRecordColumn(addInfo[[temp]], "temp", {"start", "finish"}),
before = Table.ToColumns(Table.RemoveLastN(baseData, 1)),
after = Table.ToColumns(Table.RemoveFirstN(baseData, 1)),
result = Table.FromColumns(before & after),
oneMoreResult = Table.AddColumn(result, "Column5", each Duration.TotalSeconds([Column3] - [Column2]))
in
oneMoreResult
})
in
calc
Ну и естественно можно скопировать код в отдельную функцию, или сделать копию такого запроса (оставив в нем разобранный вариант, до "подчистки"), чтобы можно было вернуться.
quasarrr, можно еще вот так создавать функции связанные с запросом. Тогда любые изменения в запросе мигрируют в функцию, с ним связанную. Очень удобно при отладке. НО, есть один нюанс, при создании запроса все входные данные, которые будут аргументами будущей функции необходимо задавать только с помощью параметров, иначе ваша итоговая функция будет неполноценной.