Power Query M循环表/通过自联接查找

时间:2017-08-23 12:21:03

标签: loops powerquery

首先,我是电源查询的新手,所以我迈出了第一步。但是我需要尝试在工作中提供一些时间,这样我才能获得一些喘息的时间来学习。

我有下表(示例):

Orig_Item       Alt_Item    
5.7             5.10
79.19           79.60
79.60           79.86
10.10           

我需要创建一个循环表并显示最终Alt_Item的列。结果如下:

Orig_Item       Alt_Item        Final_Item  
5.7             5.10            5.10    
79.19           79.60           79.86   
79.60           79.86           79.86   
10.10           

非常感谢

2 个答案:

答案 0 :(得分:1)

实际上,这对于第一次Power Query体验来说太复杂了。

如果这是你必须做的事情,那么就这样吧,但你应该意识到你开始的是一项非常艰巨的任务。

小细节:我希望最后的Final_Item为10.10。根据示例,如果Alt_Item为null,则Final_Item将为null。如果这不正确,那么这将是您相应调整下面代码的第一步。

您可以创建一个新的空白查询,在高级编辑器中复制并粘贴此代码(替换默认代码)并将Source调整为您的表名。

let
    Source = Table.Buffer(Table1),
    AddedFinal_Item = 
      Table.AddColumn(
        Source, 
        "Final_Item", 
        each if [Alt_Item] = null
             then null
             else List.Last(
                    List.Generate(
                        () => [Final_Item = [Alt_Item], Continue = true],
                        each [Continue],
                        each [Final_Item = 
                                    Table.First(
                                        Table.SelectRows(
                                            Source, 
                                            (x) => x[Orig_Item] = [Final_Item]),
                                        [Alt_Item = "not found"]
                                                        )[Alt_Item], 
                              Continue = Final_Item <> "not found"],
                        each [Final_Item])))
in
    AddedFinal_Item

此代码使用函数 List.Generate 来执行循环。 出于性能原因,在调用List.Generate之前,应始终在内存中缓冲表(Table.Buffer)。

List.Generate是最复杂的Power Query功能之一。

它需要4个参数,每个参数本身就是一个函数。

在这种情况下,第一个参数以()开头,另外3个以每个开头(从上面的大纲中可以清楚地看出:它们是对齐的)。

参数1 定义初始值:包含字段Final_Item和Continue的记录。

参数2 是继续的条件:如果找到了某个项目。

参数3 是每次迭代中的实际转换:搜索Source表(使用Table.SelectRows),其中Orig_Item等于Alt_Item。这包含在Table.First中,它返回第一条记录(如果找到)并接受默认值(如果没有找到),在这种情况下是一个记录,其字段为Alt_Item,值为&#34;未找到&#34;,从此结果返回记录字段[Alt_Item]的值,该值可以是第一个记录的值,也可以是&#34;未找到&#34;来自默认值。

如果值为&#34;未找到&#34;,则继续变为 false ,迭代将停止。

参数4 是将返回的值:Final_Item。

List.Generate返回每次迭代的所有值的列表。只需要最后一个值,因此List.Generate包含在List.Last中。

最后评论:Power Query中很少需要实际循环,我认为应该尽可能避免。但是,在这种情况下,这是一个可行的解决方案,因为您事先并不知道将遇到多少Alt_Item。 List.Generate的替代方法是使用 resursive函数 List.Accumulate 也接近循环,但迭代次数固定。

答案 1 :(得分:0)

这可以简单地通过自连接来解决,一个开放的问题是您将期望支持多少层间接访问。

假设仅一个间接级别,在Orig_Item上没有重复项,解决方案是:

let
    Source = #"Input Table",
    SelfJoin1 = Table.NestedJoin( Source, {"Alt_Item"}, Source, {"Orig_Item"}, "_tmp_" ),
    Expand1   = ExpandTableColumn( SelfJoin1, "_tmp_", {"Alt_Item"}, {"_lkp_"} ),
    ChkJoin1  = Table.AddColumn( Expand1, "Final_Item", each (if [_lkp_] = null then [Alt_Item] else [_lkp_]), type number)
in
    ChkJoin1  

这可以在常规UI中完成,使用合并查询,然后展开列并添加自定义列。

如果您想支持一个以上级别的间接,请将其转换为被调用X次的函数。对于数据驱动的间接级别,您可以将调用包装在list.generate中,将中间表放在结构化列中,尽管这是PQ的高级级别。