Power Query: как добавить один в столбец, когда заданные значения c появляются в другом столбце - PullRequest
3 голосов
/ 28 апреля 2020

У меня есть столбец идентификаторов, и я ищу способы увеличивать свои идентификаторы каждый раз, когда в моем столбце Geography появляется определенный элемент c (ItalyZ, ItalyM, UKY или UKM)

Идентификатор ItalyZ начинается с 0 и заканчивается 4000.

Идентификатор ItalyB начинается с 4000 и заканчивается в 8000.

Идентификатор UKY начинается в 0 и заканчивается в 4000.

Идентификатор UKM начинается в 4000 и заканчивается в 8000.

Однако я обновляю свой файл, и я буду таким образом, время от времени появляются новые поступления «географий» без происхождения или первых идентификаторов. Эти границы / диапазоны известны только как начало и конец.

Вот пример моих данных:

  |---------------------|------------------|    
  |       ID            |   Geography      |
  |---------------------|------------------|
  |    AB0000           |      ItalyZ      |
  |---------------------|------------------|
  |    AB4041           |      ItalyB      |
  |---------------------|------------------|
  |    BC0000           |      UKY         |
  |---------------------|------------------|
  |    BC4001           |      UKM         |
  |---------------------|------------------|
  |    NULL             |      ItalyZ      |
  |---------------------|------------------|
  |    NULL             |      ItalyZ      |
  |---------------------|------------------|
  |    NULL             |      UKY         |
  |---------------------|------------------|
  |    NULL             |      UKM         |
  |---------------------|------------------|  

Вот мой ожидаемый результат:

  |---------------------|------------------|    
  |       ID            |   Geography      |
  |---------------------|------------------|
  |    AB0000           |      ItalyZ      |
  |---------------------|------------------|
  |    AB4041           |      ItalyB      |
  |---------------------|------------------|
  |    BC0000           |      UKY         |
  |---------------------|------------------|
  |    BC4001           |      UKM         |
  |---------------------|------------------|
  |    AB0001           |      ItalyZ      |
  |---------------------|------------------|
  |    AB0001           |      ItalyZ      |
  |---------------------|------------------|
  |    AB4042           |      UKY         |
  |---------------------|------------------|
  |    BC0001           |      UKM         |
  |---------------------|------------------|  

Я пробовал много разных способов и пытался приспособить бег полные решения. Я также пытался разбить мой файл на четыре части, чтобы не иметь функции If, чередующейся между делами, и, таким образом, упростить ее, как это показано в моём мощном запросе:

 #"Added Custom2" = Table.AddColumn(#"Reordered Columns", "Sum", each if [Geography] = "UKM" then [Number AB range below 4000] + 1 
else if [Geography] = "UKY" then [Number AB range above 4000] + 1 
else if [Geography] = "ItalyB" then [Number BC range above 5000]
else [Number BC range below 5000] + 1)

Но абсолютно ничего не работает Это сводит с ума.

Ответы [ 2 ]

4 голосов
/ 29 апреля 2020

Я отвечу на еще одну упрощенную задачу, поскольку не хочу обращаться к буквенным префиксам ID.

Допустим, у нас есть следующая таблица (я включил:

ID,  Group
-----------
0,     A
1,     A
300,   B
525,   C
null,  A
null,  B
null,  B
null,  C

И хотим создать новый столбец NewID, который заменит ID.

ID,  Group, NewID
------------------
0,     A,   0
1,     A,   1
300,   B,   300
525,   C,   525
null,  A,   2
null,  B,   301
null,  B,   302
null,  C,   526

Вот метод, который использует Table.AddIndexColumn:

let
    Source = <First Table Above>,
    #"Grouped Rows" = Table.Group(Source, {"Group"}, {{"ID", each List.Max([ID]), type number}}),
    #"Added Custom" = Table.AddColumn(#"Grouped Rows", "Custom", (C) => Table.AddIndexColumn(Table.SelectRows(Source, each _[Group] = C[Group]),"NewID",C[ID],1)),
    #"Expanded Custom" = Table.ExpandTableColumn(#"Added Custom", "Custom", {"NewID"}, {"NewID"}),
    #"Removed Columns" = Table.RemoveColumns(#"Expanded Custom",{"ID"})
in
    #"Removed Columns"

Сначала мы сгруппировать по Group, чтобы найти максимальное значение ID за Group:

Group By

Затем мы добавляем новый столбец, в котором каждая строка столбца таблица , определенная путем фильтрации исходной таблицы до текущей группы и добавления столбца индекса, начиная с максимального значения ID, которое мы только что нашли. Это самый сложный шаг.

Add table column

Отсюда мы расширяем столбец таблицы Custom (выбираем столбец, которого у нас еще нет) и удаляем старый столбец ID. теперь там, где нам не хватает сортировки или набора столбцов, которые мы выбираем.

Final


Редактировать: Я сделал ошибку в приведенном выше. Обратите внимание, что NewID для Group A составляет 1,2,3 вместо 0,1,2, который я пытался.

Чтобы исправить это в этом простом примере, вы можете использовать List.Min вместо List.Max в пошаговом группировании.

В более сложном примере вам может потребоваться добавить столбец индекса в исходную таблицу, чтобы вы могли выполнить слияние с ним после расширения и использовать только новый NewID для ранее NULL ID значения, так как мы не можем гарантировать, что они являются смежными.

Вот код:

let
    Source = <First Table Above>,
    #"Added Index" = Table.AddIndexColumn(Source, "Index", 0, 1),
    #"Grouped Rows" = Table.Group(#"Added Index", {"Group"}, {{"ID", each List.Max([ID]), type number}}),
    #"Added Custom" = Table.AddColumn(#"Grouped Rows", "Custom", (C) => Table.AddIndexColumn(Table.SelectRows(Table.Sort(#"Added Index",{"ID"}), each _[Group] = C[Group]),"NewID",C[ID]+1,1)),
    #"Expanded Custom" = Table.ExpandTableColumn(#"Added Custom", "Custom", {"Index", "NewID"}, {"Index", "NewID"}),
    #"Merged Queries" = Table.NestedJoin(#"Added Index", {"Index"}, #"Expanded Custom", {"Index"}, "Expanded Custom", JoinKind.LeftOuter),
    #"Expanded Expanded Custom" = Table.ExpandTableColumn(#"Merged Queries", "Expanded Custom", {"NewID"}, {"NewID"}),
    #"Added Custom1" = Table.AddColumn(#"Expanded Expanded Custom", "ReplaceID", each if [ID] = null then [NewID] else [ID]),
    #"Removed Columns" = Table.RemoveColumns(#"Added Custom1",{"ID", "NewID"})
in
    #"Removed Columns"

Сложный шаг немного меняется:

(C) => Table.AddIndexColumn(
           Table.SelectRows(
               Table.Sort(#"Added Index", {"ID"}),
               each _[Group] = C[Group]
           ),
           "NewID", C[ID] + 1, 1
       )

Разница в том, что нам нужно добавить сортировку, чтобы после всех уже назначенных ID значений приходили значения NULL, и индексирование нуля начиналось бы с C[ID] + 1 вместо C[ID].


. версия, в которой меньше шагов (нет группировки, расширения или слияния), но немного более сложная функция:

let
    Source = <First Table Above>,    
    #"Added Index" = Table.AddIndexColumn(Source, "Index", 0, 1),
    #"Added Custom" = Table.AddColumn(#"Added Index", "Custom", (C) => Table.SelectRows(#"Added Index", each _[Group] = C[Group])),
    #"Added NewID" = Table.AddColumn(#"Added Custom", "NewID", (C) => if C[ID] = null then Table.SelectRows(Table.AddIndexColumn(Table.SelectRows(C[Custom], each _[ID] = null), "NewID", List.Max(C[Custom][ID])+1,1), each _[Index] = C[Index]){0}[NewID] else C[ID]),
    #"Removed Columns" = Table.RemoveColumns(#"Added NewID",{"Custom"})
in
    #"Removed Columns"

Первый добавленный столбец Custom - это просто индексированная исходная таблица, отфильтрованная для текущего Group. Затем мы добавляем столбец NewID, определенный как:

(считывание изнутри.)

(C) =>
  if C[ID] = null
  then Table.SelectRows(
           Table.AddIndexColumn(
               Table.SelectRows(C[Custom], each _[ID] = null),
               "NewID", List.Max(C[Custom][ID]) + 1, 1
           ),
           each _[Index] = C[Index]
       ){0}[NewID]
  else C[ID]

Как и прежде, мы берем групповую подтаблицу Custom, просто выберите пустые ID строки и индексировать их, начиная с максимального ненулевого ID плюс один. Это все еще оставляет нас с таблицей, поэтому мы просто хотим строку в этой подтаблице, которая соответствует Index из всей таблицы. Мы используем {0}[NewID] для извлечения значения из ячейки в первой (единственной) строке таблицы в столбце [NewID]. Для ненулевых значений ID предложение else просто оставляет их такими, какими они были.

3 голосов
/ 29 апреля 2020

Как и в моем другом ответе, здесь приведена упрощенная проблема игнорирования буквенных префиксов ID.

ID,  Group | NewID
-----------|------
4,     A   | 4
7,     A   | 7
300,   B   | 300
525,   C   | 525
null,  A   | 10
9,     A   | 9
null,  A   | 11
null,  B   | 301
null,  C   | 526
null,  A   | 12
null,  B   | 302

Начиная с левой части таблицы, мы хотим вычислить новый столбец NewID.

В этом ответе я напишу пользовательскую функцию, которая написана рекурсивно с использованием функции List.Generate .

Из связанной документации функция настроена следующим образом this

List.Generate(
    initial as function,                    /*Set all your initial variables*/
    condition as function,                  /*Stopping criteria.*/
    next as function,                       /*Define how to update at each step.*/
    optional selector as nullable function  /*Pick output element.*/
) as list

Определяет функцию, которая принимает столбец, потенциально содержащий нули, и заполняет нули постепенно от максимального ненулевого значения:

(Column as list) as list =>
let
    Generate =
    List.Generate(
        () => [x = Column{0}, i = 0, n = List.Max(Column)],
        each [i] < List.Count(Column),
        each [
            i = [i] + 1,
            x = if Column{i} = null then [n] + 1 else Column{i},
            n = if Column{i} = null then [n] + 1 else [n]
            ],     
        each [x]
    )
in
    Generate

Когда вы определяете функцию, она выглядит как это и может быть повторно использован в любых других запросах:

Screenshot

Вы можете использовать его, выбрав существующий столбец в существующей таблице и нажав кнопку Кнопка вызова.

Select Column

Это создаст новый список на панели запросов под названием «Вызванная функция», то есть та функция, которая применяется к выбранному вами столбцу.

* 103 3 *Invoked Function

Вы также можете создать пустой запрос и передать ему список. Например, FilterNulls({4,7,null,9,null,null}) возвращает {4,7,10,9,11,12}.

Вот как это выглядит в редакторе запросов.

New Query


То, что мы действительно хотим сделать, это использовать эту функцию как преобразование столбца в группе по операции, а затем развернуть:

let
    Source = <Data Table Source Here>,
    #"Grouped Rows" = Table.Group(Source, {"Group"}, {{"FillNulls", each FillNulls([ID]), type list}}),
    #"Expanded FillNulls" = Table.ExpandListColumn(#"Grouped Rows", "FillNulls")
in
    #"Expanded FillNulls"

Вот как это выглядит после группировки, но перед расширением:

Group By

Обратите внимание, что делает функция. Мы применяем функцию FillNulls в столбце ID для каждого отдельного Group.


Это количество шагов и сложность, аналогичные другим ответам, но используется функция, которая построенный рекурсивным способом, который может быть более знаком вам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...