У меня есть столбец идентификаторов, и я ищу способы увеличения моих идентификаторов каждый раз, когда в моем Geography столбце появляется ItalyZ, ItalyM, UKY или {{ X4}}) найден.

Идентификатор 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
Tomas Michel 28 Апр 2020 в 22:14

2 ответа

Лучший ответ

Как и в моем другом ответе, вот упрощенная проблема, игнорирующая префиксы букв 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.

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

Из связанной документации функция настроена так

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

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

Select Column

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

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.


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

2
Alexis Olson 1 Май 2020 в 22:01

Я отвечу на еще одну упрощенную задачу, поскольку не хочу обращаться к префиксам букв 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 только для ранее нулевых 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 значений приходились нулевые значения, и вместо нумерации C[ID] начинали индексировать пустые значения с C[ID] + 1.


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

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]

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

4
Alexis Olson 29 Апр 2020 в 13:24