作为一个查询函数,SUMMARIZE 执行三个操作:
- 它可以按表本身或相关表的任何列对表进行分组;
- 它可以创建新列,在行上下文和过滤上下文中计算表达式;
- 它可以产生不同级别的小计(subtotal)。
在 SUMMARIZE 的三个主要操作中,只有第一个是安全的。 另外两个操作——创建新列和计算小计——应该避免。 并不是说这些功能不起作用。 问题是 SUMMARIZE 的语义非常复杂,以至于结果可能出乎意料。 情况可能更糟:在第一次测试中结果可能看起来是正确的,但这可能只意味着 SUMMARIZE 正在静静地等着在背后捅你一刀,一旦部署到生产环境中,就会产生错误的结果,并且这个结果几乎是无法调试的 。
为了正确理解 SUMMARIZE,您必须了解集群的工作原理、行和过滤器上下文的存在有什么影响,以及扩展表在集群中的作用。 我们一次一步地介绍这些概念:首先是聚类,然后是扩展表在聚类中的作用,最后是同一公式中同时存在行和过滤器上下文的影响。
一,聚类(Clustering)
聚类是 SUMMARIZE 用来计算其结果的一种技术,我们使用只有七行的表来引入聚类。
SUMMARIZE (
Sales,
Sales[Color],
"Sales", SUM ( Sales[Amount] )
)
直觉上,我们可能会认为 SUMMARIZE 是从按 Sales[Color] 对 Sales 进行分组开始的; 然后它通过在颜色上创建过滤器上下文来计算具有相同颜色的所有行的 Amount 总和来迭代结果。 不幸的是,这将是 SUMMARIZE 执行的步骤的近似值。 它的作用更复杂。
因为查询需要按颜色分组,所以 SUMMARIZE 将表拆分为分区——每种颜色一个。 此操作称为聚类。 聚类是基于用于分组的列创建分区。 SUMMARIZE 首先根据颜色对表进行聚类,然后通过创建将计算限制为迭代聚类的过滤上下文来计算每个聚类的表达式。 因为我们按 Sales[Color] 分组,SUMMARIZE 根据颜色将 Sales 表拆分为三个集群。
因为我们按颜色分组,所以每个集群都由一种颜色标识。 在我们的场景中,Sales[Color] 是集群标头。 簇头是 SUMMARIZE 的 groupby 部分中使用的一组列。 簇头可以包含多列,即使在第一种情况下我们只有一列。
集群准备就绪后,SUMMARIZE 计算三个集群的 SUM (Sales[Amount]) 值。 这是 SUMMARIZE 倾向于参与的许多恶作剧中的第一个:为了将计算限制在单个集群中,SUMMARIZE 不会创建仅包含集群标头的过滤器上下文。 相反,它使用集群中的所有列创建过滤上下文,过滤集群中存在的值。
对于蓝色集群,我们有三辆自行车,价格为 300.00 美元,四件衬衫,价格为 400.00 美元。 因此,为 Blue 集群计算的表达式如下所示:
CALCULATE (
SUM ( Sales[Amount] ),
FILTER (
ALL ( Sales ),
( Sales[Color], Sales[Product], Sales[Quantity], Sales[Amount] )
IN {
( "Blue", "Bike", 3, 300 ),
( "Blue", "Shirt", 4, 400 )
}
)
)
表达式过滤所有列,要求所有列的值都属于簇中的一行。 您可以通过运行以下查询来仔细检查此行为,作为测试:
SUMMARIZE (
Sales,
Sales[Color],
"Test", ISFILTERED ( Sales[Quantity] )
)
查询在 Test 中返回 TRUE。 这表明 Sales[Quantity] 正在被主动过滤,即使它没有出现在 groupby 列中的任何地方。 事实上,Sales[Quantity] 在由 SUMMARIZE 计算的表达式中被过滤,因为 Sales[Quantity] 是为按颜色切片而创建的集群的列之一。 虽然净效果看起来一样,但事实并非如此。 虽然每个簇确实只过滤一种颜色,但实际上簇过滤的不仅仅是颜色。
让我们看看为什么这是相关的。 在继续之前尝试猜测以下查询的结果:
SUMMARIZE (
Sales,
Sales[Color],
"Sales", SUM ( Sales[Amount] ),
"All Sales",
CALCULATE (
SUM ( Sales[Amount] ),
REMOVEFILTERS ( Sales[Color] )
)
)
如果我根据常识猜测,我会说 All Sales 返回所有产品的销售额。 相反,All Sales 的结果不是销售额的总计; 这是一个非常奇怪的数字,只有了解聚类才能理解。