[知识体系] 理解 SUMMARIZECOLUMNS

  [复制链接]
查看93736 | 回复111 | 2021-2-21 18:51:55 | 显示全部楼层 |阅读模式
SUMMARIZECOLUMNS 函数是一种更灵活、更高效的 SUMMARIZE 实现方式。在编写查询的时候,你可以优先考虑 SUMMARIZECOLUMNS

SUMMARIZECOLUMNS
  1. SUMMARIZECOLUMNS( <groupBy_columnName>, [< groupBy_columnName >] …, [<filterTable>]…,[<name>, <expression>] … )
复制代码
  1. SUMMARIZECOLUMNS (
  2.           <group_by_column1>, [<group_by_column2>, ...],
  3.           [<filterTable1>, <filterTable2>, ...],
  4.           [<column1_name>, { <column1_expression> | IGNORE (<group_by_column> ) } ],
  5.           [<column2_name>, { <column2_expression> | IGNORE (<group_by_column> ) } ],
  6.           [...]
  7. )
复制代码

SUMMARIZECOLUMNS 包含来自分组列生成的组合表。当至少一个表达式返回非空值的时候,整行才会包括在返回的表中。如果所有表达式对一行求值为空,则返回的表中不包括该行。

参数属性描述
GroupBy_ColumnName可选

可重复
用于分组的列或调用 ROLLUPGROUPROLLUPADDISSUBTOTAL 函数来计算分组小计的列
FilterTable可选

可重复
提供筛选上下文的表或表表达式.

表达式可以嵌入到 NONVISUAL 函数中,该函数将 SUMMARIZECOLUMNS 函数中的筛选条件标记为不影响度量值,仅应用于分组的列。
Name可选

可重复
添加的新列名称
Expression可选

可重复
新列的表达式

示例用法

例如,你可以这样使用 SUMMARIZECOLUMNS 编写 SUMMARIZE 的第一个示例:
  1. EVALUATE
  2. SUMMARIZECOLUMNS (
  3.     'Date'[Calendar Year],
  4.     "Quantity", SUM ( Sales[Quantity] )
  5. )
复制代码


7070211936381.jpeg



如果不定义任何新列,则结果不会筛选指定列中存在的任何值。
  1. EVALUATE
  2. SUMMARIZECOLUMNS (
  3. 'Date'[Calendar Year]
  4. )
复制代码


7070211936382.jpeg


等价形式

实际上,它的内部行为与 SUMMARIZE 有所不同。SUMMARIZECOLUMNS 从输出中删除所有列表达式为空值的行。例如,第一个示例的语法对应于以下内容:
  1. EVALUATE
  2. FILTER (
  3.     ADDCOLUMNS (
  4.         VALUES ( 'Date'[Calendar Year] ),
  5.         "Quantity", CALCULATE (
  6.             SUM ( Sales[Quantity] )
  7.         )
  8.     ),
  9.     NOT ISBLANK ( [Quantity] )
  10. )
复制代码
添加筛选器

SUMMARIZECOLUMNS 是生成查询时的一个常用函数。在不使用筛选表的情况下,由分组列为表达式提供筛选上下文。当使用筛选表(<filterTable1>)的时候,你可以假设其行为类似于 SUMMARIZE 的第一参数,即可以对通过多对一关系链访问的所有列进行分组。然而,使用 SUMMARIZECOLUMNS 中的筛选表可以做得更多,特别是在与双向交叉筛选相关的数据模型中。


如果你只想获取在销售表中有记录的年份,则需要将销售表指定为筛选上下文。但是,由于SUMMARIZECOLUMNS 必须将表筛选器置于函数内部,因此表筛选器不能作为 CALCULATECALCULATETABLE 的筛选器参数筛选 SUMMARIZECOLUMNS。故以下语法无效:
  1. EVALUATE
  2. CALCULATETABLE (
  3.     SUMMARIZECOLUMNS ( 'Date'[Calendar Year] ),    //此筛选无效
  4.     Sales
  5. )
复制代码

“SummarizeColumns() 和 AddMissingItems() 不能用于此上下文中”


相反,你可以指定一个或多个用作筛选的表,这些筛选表等价于在外部 CALCULATETABLE 中指定的筛选器参数:
  1. EVALUATE
  2. SUMMARIZECOLUMNS (
  3.     'Date'[Calendar Year],
  4.     Sales
  5. )
复制代码

该查询返回一个三年的列表,该列表与第一个查询过滤后的列表相同,在第一个查询中,我们指定了一个聚合销售表 Quantity 列的表达式。



7070211936383.jpeg

和 SUMMARIZE 一样,对 SUMMARIZECOLUMNS 的介绍也会涉及到扩展表的概念,在高级原理章节对此概念有详细解释。
筛选器不支持布尔表达式

在添加筛选表的时候需要注意,CALCULATECALCULATETABLE 的布尔表达式形式的筛选器参数不可直接用于 SUMMARIZECOLUMNS。你需要将其改写为表形式的筛选器:
  1. EVALUATE
  2. SUMMARIZECOLUMNS (
  3.     'Date'[Calendar Year],
  4.      Customer[Education] = "High School"     //不支持布尔表达式
  5. )

  6. EVALUATE
  7. SUMMARIZECOLUMNS (
  8.     'Date'[Calendar Year],
  9.     FILTER (
  10.         ALL ( Customer[Education] ),
  11.         Customer[Education] = "High School"   //支持表筛选器
  12.     )
  13. )
复制代码
其他注意事项

SUMMARIZE 接受来自外部的筛选上下文,而 SUMMARIZECOLUMNS 在这方面受到限制。这是两者的一个重要区别,特别是当你需要通过代码动态生成 DAX 查询时。建议在 SUMMARIZECOLUMNS 筛选器参数中直接加入筛选器,而不是依赖由 CALCULATE 或 CALCULATETABLE 定义的外部筛选上下文。不过,你仍然可以在这两个函数中使用布尔表达式过滤 SUMMARIZECOLUMNS 的结果。


SUMMARIZECOLUMNS 不需用表做为第一参数,你可以在定义用于分组的列之后选择性的指定一个或多个表作为筛选上下文的一部分,然后,你必须在接下来指定用于计值的筛选器,因为 SUMMARIZECOLUMNS 不具有外部筛选上下文。例如,以下查询返回日历年和产品类别的所有可能组合(总共 21 行):
  1. EVALUATE
  2. SUMMARIZECOLUMNS (
  3.     'Date'[Calendar Year],
  4.      Product[Class]
  5. )
复制代码


7070211936384.jpeg

在之前的示例中,SUMMARIZECOLUMNS 具有与 CROSSJOIN 相同的行为。通常, SUMMARIZECOLUMNS 被用于更复杂的需求,而对于此类案例,你可以使用 CROSSJOIN

如果要求日历年和产品类别的组合至少在销售表存在一条记录,可以使用以下公式(结果共 9 行):
  1. EVALUATE
  2. SUMMARIZECOLUMNS (
  3.     'Date'[Calendar Year],
  4.     Product[Class],
  5.     Sales
  6. )
复制代码


7070211936385.jpeg



下面的查询返回产品单价大于 3000 元的所有日历表年份和产品的组合(共 7 行):
  1. EVALUATE
  2. SUMMARIZECOLUMNS (
  3.     'Date'[Calendar Year],
  4.     Product[Class],
  5.     CALCULATETABLE (
  6.         Product,
  7.         Product[Unit Price] > 3000
  8.     )
  9. )
复制代码


7070211936386.jpeg



最后一个查询同样返回产品单价大于 3000 元的所有年份和产品的组合,并且要求每个组合在销售表至少存在一条销售记录(共 3 行),在本例中,我们还将数量的求和添加为新列:
  1. EVALUATE
  2. SUMMARIZECOLUMNS (
  3.     'Date'[Calendar Year],
  4.     Product[Class],
  5.     CALCULATETABLE (
  6.         Sales,
  7.         Product[Unit Price] > 3000
  8.     ),
  9.     "Quantity", SUM ( Sales[Quantity] )
  10. )
复制代码


7070211936387.jpeg


IGNORE 保留空行

如果把 Sales[Quantity]的总和添加为新列,你也许会使用之前来自产品表的筛选器。实际上,SUMMARIZECOLUMNS 默认删除在所有列表达式中具有空白结果的行。你可以使用 IGNORE 函数保留它们,如下例所示:
  1. EVALUATE
  2. SUMMARIZECOLUMNS (
  3.     'Date'[Calendar Year],
  4.     Product[Class],
  5.     CALCULATETABLE (
  6.         Product,
  7.         Product[Unit Price] > 3000
  8.     ),
  9.     "Quantity", IGNORE (
  10.         SUM ( Sales[Quantity] )
  11.     )
  12. )
复制代码


7070211936388.jpeg


表达式计值环境(重要)

在 SUMMARIZECOLUMNS 中计值的表达式只有筛选上下文,而没有行上下文(SUMMARIZE 提供行上下文)。但是,你可以使用 VALUES 访问分组列,函数返回一个包含单行单列的表,将自动转换为标量值,如下面的示例所示。
  1. EVALUATE
  2. SUMMARIZECOLUMNS (
  3.     'Date'[Calendar Year],
  4.     Product[Class],
  5.     CALCULATETABLE (
  6.         Sales,
  7.         Product[Unit Price] > 3000
  8.     ),
  9.     "Upper", UPPER (
  10.         VALUES ( Product[Class] )
  11.     ),
  12.     "Quantity", SUM ( Sales[Quantity] )
  13. )
复制代码


7070211936389.jpeg


深入了解 SUMMARIZECOLUMNS

SUMMARIZECOLUMNS 不能在绝大部分度量值中使用,虽然在某些环境下可以得到正确结果,但你最好不要依赖这种方法。当你需要在度量值中执行分组和新建列时,最可靠的方式是SUMMARIZE+ADDCOLUMNS

为什么不支持度量值

SUMMARIZECOLUMNS 不支持上下文转换时发生的计算,这个特性使它无法在大多数度量值中使用。你可以在调用 CALCULATE 的度量值中使用它,但是遇到任何上下文转换的情况就会出错,而像 Excel 和 Power BI 生成的图表在计算时几乎都包含了上下文转换,仅少数 KPI 类型图表除外。

ROLLUPADDISSUBTOTAL

使用 ROLLUPADDISSUBTOTAL,你可以创建小计,同时添加标记列,显示当前行是否为指定列的小计。这是一种将 SUMMARIZE 中的 ROLLUP 函数和 ISSUBTOTAL 函数组合使用的简便方法。以下查询为日历表年份列添加小计:
  1. EVALUATE
  2. SUMMARIZECOLUMNS (
  3.     Product[Class],
  4.     Product[Weight Unit Measure],
  5.     ROLLUPADDISSUBTOTAL ( 'Date'[Calendar Year],
  6. "Subtotal Year" ),
  7.     CALCULATETABLE (
  8.         Sales,
  9.         Product[Unit Price] > 3000
  10.     ),
  11.     "Quantity", SUM ( Sales[Quantity] )
  12. )
复制代码


70702119363810.jpeg



可以多次调用 ROLLUPADDISSUBTOTAL,也可以在对 ROLLUPADDISSUBTOTAL 的一次调用中包含多组列引用和列名,两者结果相同。

ROLLUPGROUP



如果要为两列或更多列创建单个小计,可以使用 ROLLUPGROUP。下面的查询为 Class 和 Weight Unit Measure 列共同创建一个小计,也为每个年份创建小计。实际上,你会看到每年所有产品的小计,然后是所有年份和产品的总计:
  1. EVALUATE
  2. SUMMARIZECOLUMNS (
  3.     ROLLUPADDISSUBTOTAL (
  4.         'Date'[Calendar Year], "Subtotal Year",
  5.         ROLLUPGROUP (
  6.             Product[Class],
  7.             Product[Weight Unit Measure]
  8.         ), "Subtotal Product"
  9.     ),
  10.     CALCULATETABLE (
  11.         Sales,
  12.         Product[Unit Price] > 1000
  13.     ),
  14.     "Quantity", SUM ( Sales[Quantity] )
  15. )
复制代码


70702119363811.jpeg



ROLLUPADDISSUBTOTAL 内部的参数位置很重要,如果反转它们的顺序,你将得到一个为每个产品类别和重量单位计算所有年份的小计,逻辑会显著不同,只有总计保持不变。
回复

使用道具 举报

911net | 2021-4-24 13:05:48 来自手机 | 显示全部楼层
我也顶起出售广告位
回复

使用道具 举报

smh | 2021-6-11 10:15:26 | 显示全部楼层
啥玩应呀
回复

使用道具 举报

水仙水瓶 | 2021-9-2 13:45:43 来自手机 | 显示全部楼层
我是个凑数的。。。
回复

使用道具 举报

SilverPOLO | 2021-10-4 09:00:51 | 显示全部楼层
谢谢,一直在学习云发教育课程!
回复

使用道具 举报

cls10000 | 2021-10-12 08:17:06 来自手机 | 显示全部楼层
回个帖子,下班咯~
回复

使用道具 举报

奇骏 | 2021-11-1 22:04:22 来自手机 | 显示全部楼层
好帖必须得顶起
回复

使用道具 举报

e70f | 2021-11-4 21:04:03 | 显示全部楼层
没人回帖。。。我来个吧
回复

使用道具 举报

大阿哥 | 2021-11-13 11:29:16 来自手机 | 显示全部楼层
我也来支持一下,很喜欢这里老师
回复

使用道具 举报

教授2 | 2021-11-16 19:29:35 | 显示全部楼层
好,很好,非常好!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则