从索引列表中引用列名

Referencing a column name from an indexed list

背景: 我正在尝试创建包含动态列名称的查询,这样如果用户更改 table 中的列名称,任何转换的逻辑仍然遵循。

这个问题很简单,但很难用几句话来解释。我试图分解我所做的一切,以轻松显示我遇到的问题。如果很明显,请直接跳到最后的问题。

动态列的演示: 要开始使列名称动态化,我使用:

DynamicNameHeader = Table.ColumnNames(Source)

这会根据原始 table 创建一个列名列表。如果在电子表格中更改了 Table 名称,则此列表会动态更新。此列表可用于间接引用 M 代码中的列。

作为一个例子来说明这一点,我在这里将 Table1 中的 Column1 更改为 Hello 并在刷新数据后将输出的 table 列更新为相应地阅读 Hello

通过引用 DynamicNameHeader 列表并为所需的列建立索引,这是可行的。该代码还演示了可以通过将文本更改为大写并对列重新排序来实现的简单转换。

M代码:

let
    Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
   
DynamicHeaderNames =Table.ColumnNames(Source),

    #"Uppercased Text" = Table.TransformColumns(#"Source",{{DynamicHeaderNames{0}, Text.Upper, type text}, {DynamicHeaderNames{1}, Text.Upper, type text}}),
    #"Reordered Columns" = Table.ReorderColumns(#"Uppercased Text",{DynamicHeaderNames{1}, DynamicHeaderNames{0}})
in
    #"Reordered Columns"

这只是一个简单的示例,用于展示我如何尝试以这种方式集成动态列。

问题 这是已在输出 table 中排序的实际数据的简单版本,因此第 1 列中的数据优先于第 2 列中的值。第 3 列中的数字仅对应于第 2 列中的值。

实现此输出的工作 M 代码:

let
    Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],

    //combine the columns
    #"Added Custom" = Table.AddColumn(Source, "Custom", each
        let 
            L1 = if [Column2] = "-" then {[Column1]}
                    else List.Combine({{[Column1]},Text.Split([Column2],"#(lf)")}),
            L2 = if [Column2] = "-" then {[Column3]}
                    else List.Combine({{"-"},Text.Split([Column3],"#(lf)")})
        in 
            List.Zip({L1,L2})),
    #"Removed Columns1" = Table.RemoveColumns(#"Added Custom",{"Column1", "Column2", "Column3"}),

    //split the combined columns
    #"Expanded Custom" = Table.ExpandListColumn(#"Removed Columns1", "Custom"),
    #"Extracted Values" = Table.TransformColumns(#"Expanded Custom", 
        {"Custom", each Text.Combine(List.Transform(_, Text.From), ";"), type text}),
    #"Split Column by Delimiter" = Table.SplitColumn(#"Extracted Values", 
        "Custom", Splitter.SplitTextByDelimiter(";", QuoteStyle.Csv), {"Column1", "Column3"})
in
    #"Split Column by Delimiter"

我希望像简化示例中那样使此代码动态化,但是我 运行 在添加“自定义列”步骤时遇到很多语法问题。

本质上,我希望像以前一样通过索引 DynamicNameHeader 列表来间接引用第 1、2 和 3 列。这可能吗?重要的是,这不仅允许用户更改列名,而且对数据的转换也可以动态引用相关列。此自定义列转换几乎是唯一证明困难的步骤,因为它使用 [] 似乎与 DynamicNameHeader{x} 不兼容。

我希望这个解释足够清楚,可以理解我想要实现的目标,如果有人对此问题有任何解决方案,我将不胜感激。

您发布的 M 代码 并没有真正 return 您显示的结果,但这里是一个如何在 headers 中使用未定义列的示例您的自定义列。

它涉及添加一个 Index 列来分类。

请注意,我还替换了示例数据中的空值,因为 Text.Split 函数将失败并返回空值

    Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],

allCols=Table.ColumnNames(Source),
    col1 = allCols{0},
    col2 = allCols{1},
    col3 = allCols{2},

IDX = Table.AddIndexColumn(Source,"IDX",0,1),
    #"Replaced Value" = Table.ReplaceValue(IDX,null,"",Replacer.ReplaceValue,allCols),
    #"Added Custom" = Table.AddColumn(#"Replaced Value", "lists", each let 
            col2List = Text.Split(
                Table.Column(#"Replaced Value",col2){[IDX]},
                 "#(lf)"),
            col3List = Text.Split(
                Text.From(Table.Column(#"Replaced Value",col3){[IDX]}),
                "#(lf)")
        in 
            List.Zip({col2List,col3List}))

编辑

这是一个 M-Code 的示例,它对实际的列名不敏感,并且会根据您显示的输入生成您显示的输出:

let
    Source = Excel.CurrentWorkbook(){[Name="Table10"]}[Content],

allCols=Table.ColumnNames(Source),
    col1 = allCols{0},
    col2 = allCols{1},
    col3 = allCols{2},

IDX = Table.AddIndexColumn(Source,"IDX",0,1),
#"Added Custom" = Table.AddColumn(IDX, "Custom", each if Table.Column(IDX,col2){[IDX]} = "-" 
    then 
       List.Zip({{Table.Column(IDX,col1){[IDX]}},{Text.From(Table.Column(IDX,col3){[IDX]})}}) 
    else 
      List.InsertRange(
        List.Zip({
        Text.Split(Table.Column(IDX,col2){[IDX]},"#(lf)"),
        Text.Split(Table.Column(IDX,col3){[IDX]},"#(lf)")}),
            0,{{Table.Column(IDX,col1){[IDX]},"-"}})),

    #"Removed Columns" = Table.RemoveColumns(#"Added Custom",List.Combine({{"IDX"}, allCols})),
    #"Expanded Custom" = Table.ExpandListColumn(#"Removed Columns", "Custom"),
    #"Extracted Values" = Table.TransformColumns(#"Expanded Custom", 
        {"Custom", each Text.Combine(List.Transform(_, Text.From), ";"), type text}),
    #"Split Column by Delimiter" = Table.SplitColumn(#"Extracted Values", "Custom", 
        Splitter.SplitTextByDelimiter(";", QuoteStyle.Csv), {col1, col3}),
    #"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{col1, type text}, {col3, type text}})
in
    #"Changed Type"