为了解决这样的问题,我先做一个具体的例子,然后概括一下。我在 Excel 中制作了一个小表格,如下所示:
| Code1 |
Code2 |
2-Jul-20 |
3-Jul-20 |
4-Jul-20 |
5-Jul-20 |
6-Jul-20 |
| ERT |
EXC |
10 |
|
6 |
15 |
2 |
| ERT |
EXC |
2 |
3 |
|
23 |
1 |
| CON |
HOR |
|
|
3 |
|
|
| CON |
HOR |
6 |
|
2 |
356 |
3 |
然后我在表中单击并创建了一个引用它的 Power Query。打开 Power Query 编辑器后,主页选项卡上有一个分组依据功能。在这样的玩具示例中选择所需的列和 Sum 函数非常简单。
然后,我打开高级编辑器查看自动生成的代码。它看起来像这样:
let
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Grouped Rows orig" = Table.Group(Source, {"Code1", "Code2"}, {{"2-Jul-20", each List.Sum([#"2-Jul-20"]), type nullable number}, {"3-Jul-20", each List.Sum([#"3-Jul-20"]), type nullable number}, {"4-Jul-20", each List.Sum([#"4-Jul-20"]), type nullable number}, {"5-Jul-20", each List.Sum([#"5-Jul-20"]), type nullable number}, {"6-Jul-20", each List.Sum([#"6-Jul-20"]), type nullable number}})
in
#"Grouped Rows orig"
通常,Power Query 表达式是应用于表的一系列转换,其中每个转换都对从前一个返回的表进行操作。在这里,我们从原始表作为“源”开始,然后进行分组。参数有点乱,但我们拥有的是:(1)输入表,(2)要分组的列名列表,以及(3)3项列表的列表,每个列表描述一个聚合列。子列表具有输出列名、进行聚合的函数和数据类型。
在 Power Query 中,“each”是单个参数函数的语法糖,其参数只是一个下划线。而且,当您有记录或行时,您可以只使用 [column] 而不是 _[column]。
那么如何概括你想做的操作呢?我的第一个想法是,根据您的描述,一个方便的分组函数应该有两个参数。第一个是要分组的表,第二个是从左边开始分组的列数。如果您没有将它们连续排列,当然,您可以做其他事情。
sumFromColumn = (t, n) => let
cList = Table.ColumnNames(t),
toGroup = List.FirstN(cList, n),
toSum = List.RemoveFirstN(cList, n),
sumFunc = (cName) => {cName, each List.Sum(Record.Field(_, cName)), type nullable number}
in Table.Group(t, toGroup, List.Transform(toSum, each sumFunc(_))),
#"Grouped Rows" = sumFromColumn(Source, 2), // Group by the first 2 columns and sum the rest
这是我做的泛化函数,看起来和接口生成的原始Table.Group操作相匹配。
let 语句安排事物的可读性,但并不暗示它们发生的特定顺序。Power Query 找出依赖关系并以所需的任何顺序执行语句。
表的列名列表定义为cList,分为toGroup和toSum。然后, sumFunc 被定义为一个函数,该函数采用列名并返回定义聚合操作所需的 3 项列表。在 Power Query 中,函数可以以任何方式返回其他函数。所以在这里我们定义了一个返回列表的函数,其中包含一个函数。然后我们可以使用 List.Transform 获取聚合列的列表并将其转换为 Table.Group 的适当参数。
最后,实际的 group by 是通过 sumFromColumn(Source, 2) 之类的调用完成的,这相当于对列名进行硬编码的原始语句。
| Code1 |
Code2 |
2-Jul-20 |
3-Jul-20 |
4-Jul-20 |
5-Jul-20 |
6-Jul-20 |
| ERT |
EXC |
12 |
3 |
6 |
38 |
3 |
| CON |
HOR |
6 |
|
5 |
356 |
3 |
这可以很容易地更改为 sumFromColumn(Source, 1),在这种情况下它将减少到两行,但是第二列是非数字的,将成为错误值。
或者,您可以使用 sumFromColumn(Source, 3),它不会相加,因为按列组合在一起的分组是不同的。
通过这种方式,您可以轻松聚合任意数量的列,而无需关心它们的名称。我推荐 microsoft.com 上的 Power Query M 文档和一般的函数式编程。