Извлеките дату начала и окончания отпуска по болезни в запросе мощности (пробелы и острова)

Я хотел бы иметь максимальную и минимальную дату различных типов отсутствия для каждого сотрудника проекта. Я хотел бы иметь это в Power BI, но не знаю, как это сделать.

Есть 3 столбца, которые следует сгруппировать: идентификатор проекта, идентификатор человека и статус времени.

Я думал о группировке также по месяцу и году, но тогда, если возникнет ситуация, когда в одном месяце будет два больничных, это не будет работать должным образом. Вот пример данных:

И результат должен быть таким:

Спасибо.

Вот образец данных:

Project ID  Person ID   Time Status     Date
10          1           Sick leave      21.06.2024
10          1           Sick leave      09.07.2024
10          1           Sick leave      10.07.2024
10          1           Sick leave      11.07.2024
10          1           Sick leave      12.07.2024
9           2           Annual leave    12.08.2024
9           2           Annual leave    13.08.2024
9           2           Annual leave    14.08.2024
9           2           Annual leave    15.08.2024
9           2           Annual leave    31.08.2024

Можете ли вы вставить свои данные в виде копируемого текста уценки?

davidebacci 22.07.2024 10:38

я добавил это

Ulewsky 22.07.2024 11:29

В SQL такого рода проблемы называются «Пробелы и острова» и обычно решаются с помощью оконных функций и PARTITION BY. Возможно, вы могли бы сделать что-то неуклюжее в M с упорядочиванием по идентификатору проекта, идентификатору человека, временному статусу, дате, а затем AddIndexColumn и самостоятельному присоединению, но похоже, что в DAX есть оконные функции.

Martin Smith 22.07.2024 12:20

Как определить, когда заканчивается один отпуск и начинается второй больничный, если отпусков несколько?

horseyride 22.07.2024 12:44

Я только хотел сгруппировать то, что происходит по дням

Ulewsky 22.07.2024 14:58
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
5
95
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

let
    Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content],
    #"Changed Type" = Table.TransformColumnTypes(Source,{{"Project ID", Int64.Type}, {"Person ID", Int64.Type}, {"Time Status", type text}, {"Date", type date}}),
    #"Added Custom" = Table.AddColumn(#"Changed Type", "Sequence", each try if Value.Is( Record.Field( #"Changed Type"{[Project ID = [Project ID], Date =  Date.AddDays( [Date],-1)] }, "Date") , type date) then null else [Date] otherwise [Date]),
    #"Filled Down" = Table.FillDown(#"Added Custom",{"Sequence"}),
    #"Grouped Rows" = Table.Group(#"Filled Down", {"Project ID", "Person ID", "Time Status", "Sequence"}, {{"Start", each List.Min([Date]), type date}, {"End", each List.Max([Date]), type date}}),
    #"Renamed Columns" = Table.RenameColumns(#"Grouped Rows",{{"Sequence", "Date"}}),
    #"Changed Type1" = Table.TransformColumnTypes(#"Renamed Columns",{{"Date", type date}})
in
    #"Changed Type1"

Он не работает для большого объема данных, возвращает дату в столбце «Последовательность».

Ulewsky 23.07.2024 10:43

Я думал, что другое решение сработало для вас, поскольку вы приняли его как ответ? Это решение работает с вашими примерными данными, поэтому добавьте больше данных, чтобы показать, где оно не работает, чтобы протестировать его или попробовать решение Рона.

davidebacci 23.07.2024 10:46

Да да, я просто хотел ответить на все ваши идеи, но спасибо за усилия, я не проверяю решение Рона

Ulewsky 23.07.2024 10:50

Это должно возвращать дату в столбце последовательности. Я не использую индекс, поскольку в этом нет необходимости, если у нас уже есть дата. Затем столбец последовательности переименовывается по дате, чтобы соответствовать ожидаемым результатам.

davidebacci 23.07.2024 11:00

Я добавил функцию GetStartAndEndDates для проверки дат[i]-dates[i-1] для каждого projectId, personId и timeStatus.

Если date[i]-dates[i-1] > 1, я предполагаю, что date[i] — это начало нового «отпуска».

let
  Source = Excel.CurrentWorkbook(),
  Navigation = Source{[Name = "Table1"]}[Content],
  GetStartAndEndDates = (source as table)=> 
    let 
      sorted = Table.Sort(source, {{"Date", Order.Ascending}}),
      addIndex = Table.AddIndexColumn(sorted, "Index", 0, 1, Int64.Type),
      addDuration = Table.AddColumn(addIndex, "Duration", each if [Index] = 0 then 0 else Duration.Days([Date] - addIndex[Date]{[Index]-1}) ),
      addKey = Table.AddColumn(addDuration, "Key", each if [Index] = 0 then 0 else if [Duration] <= 1 then null else [Index]),
      filled = Table.FillDown(addKey, {"Key"}),
      results = Table.Group(filled, {"Key"}, {{"Start Date", each List.Min([Date]), type nullable date}, {"End Date", each List.Max([Date]), type nullable date}})
    in 
      results,
  grouped = Table.Group(Navigation, {"Project ID", "Person ID", "Time Status"}, {{"All", each _, type nullable table[#"Project ID" = any, #"Person ID" = any, #"Time Status" = any, Date = any]}}),
  startEndDates = Table.AddColumn(grouped, "StartEndDates", each GetStartAndEndDates([All])),
  expanded = Table.ExpandTableColumn(startEndDates, "StartEndDates", {"Start Date", "End Date"}, {"Start Date", "End Date"}),
  removed = Table.RemoveColumns(expanded, {"All"})
in
  removed
Ответ принят как подходящий

Если у вас большой набор данных, следующие действия будут выполняться значительно быстрее.

Предполагается, что данные уже отсортированы, как показано в вашем примере, — по датам по возрастанию внутри каждого Project ID | Person ID. Если это не так, то их необходимо будет отсортировать, что увеличит время обработки.

Он использует столбец Index и 4-й и 5-й аргументы функции Table.Group, чтобы обеспечить группировку по последовательным датам:

let
    Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content],
    #"Changed Type" = Table.TransformColumnTypes(Source,{
        {"Project ID", Int64.Type}, {"Person ID", Int64.Type}, {"Time Status", type text}, {"Date", type date}}),
    #"Added Index" = Table.AddIndexColumn(#"Changed Type", "Index", 0, 1, Int64.Type),


    #"Grouped Rows" = Table.Group(#"Added Index", {"Project ID", "Person ID", "Time Status","Date", "Index"}, {
        {"Start Date", each List.Min([Date]), type date},
        {"End Date", each List.Max([Date]), type date}
        }, GroupKind.Local,(x,y)=>Duration.Days(y[Date]-x[Date])- (y[Index]-x[Index]) ),
        
    #"Removed Columns" = Table.RemoveColumns(#"Grouped Rows",{"Index"})
in
    #"Removed Columns"

Умное решение, Рон, проголосовали за.

davidebacci 22.07.2024 20:39

Действительно хорошее решение, к тому же очень быстрое, спасибо

Ulewsky 23.07.2024 11:53

Другие вопросы по теме