SUMMARIZECOLUMNS 的疑似 bug(1)引言
SUMMARIZECOLUMNS 的疑似 bug(2)SUMX 在总计行
SUMMARIZECOLUMNS 的疑似 bug(3)总计行是否关键点
SUMMARIZECOLUMNS 的疑似 bug(4)验证触发条件
SUMMARIZECOLUMNS 的疑似 bug(5)最终结论
前言
与 Power Pivot in Excel 通过 MDX 计算透视表的方式不同,PowerBI 在代码层面主要是通过 SUMMARIZECOLUMNS 函数计算报表中各个视觉对象,它实现了 MDX 中的 auto-exist 功能并具有诸多特性,能够在许多场景中代替ADDCOLUMNS+ SUMMARIZE的应用。
在实践中可以发现,在特定的情况下,SUMMARIZECOLUMNS的计算结果似乎并不符合 DAX 理论,疑似 bug。
疑似 BUG
案例文件 下载
报表环境
数据表
- DFact, 包含两列:Date 和 Amount
- Dates,日期表,包含 Date, Year, Month Num, Month, YM 5 列
表间关系
Dates 1 — * DFact,以 [Date] 关联 Dates 和 DFact,Dates 为一端,DFact 为多端
度量值
SumAmount = SUM('DFact'[Amount])
// 计算结果疑似 bug 的度量值
SumxBug = SUMX(VALUES(Dates[Year]),[SumAmount])
MaxxBug = MAXX(VALUES(Dates[Year]),[SumAmount])
MinxBug = MINX(VALUES(Dates[Year]),[SumAmount])
ConcatBug = CONCATENATEX(VALUES(Dates[Year]),[SumAmount],"+")
// 计算结果符合预期的度量值
SumxCorrect = SUMX(KEEPFILTERS(VALUES(Dates[Year])),[SumAmount])
MaxxCorrect = MAXX(KEEPFILTERS(VALUES(Dates[Year])),[SumAmount])
MinxCorrect = MINX(KEEPFILTERS(VALUES(Dates[Year])),[SumAmount])
ConcatCorrect = CONCATENATEX(KEEPFILTERS(VALUES(Dates[Year])),[SumAmount],"+")
报表
切片器:包含 Dates[Year] ,Dates[Month Num] ,选择 2019年1月、2019年2月、2020年11月、2020年12月
矩阵:以 Dates[Year] ,Dates[Month Num] 为行,以度量值 [SumBug] 为值
理论预期
按照 DAX 理论,上图中 Year = 2019 总计行计算SumxBug的过程如下:
SumxBug = SUMX(VALUES(Dates[Year]),[SumAmount])
外部筛选器
- 切片器提供筛选器A
由于选择了 2019年1、2月,2020年11、12月,形成固化筛选器(arbitrarily shaped filter),在代码层面等同于 TREATAS ({ ( 2019, 1 ), ( 2019, 2 ), ( 2020, 11 ), ( 2020, 12 ) },Dates[Year], Dates[Month Num]))
- 报表行标题提供筛选器B,在 Year = 2019 总计行
Dates[Year] = 2019
两个筛选器中把 Year 标记为 Year1 和 Year2 是故意的,1和2用于标记该筛选器的来源,用于在后续运算时加以区分,并不是说这是两个不同的列。这种做法在之前的 研究《白皮书-理解DAX查询计划》中的案例(四)优化方案2 一文介绍过,DAX 底层也是这么干的。
度量值内部筛选器
- 筛选器C,由
SUMX迭代器行上下文转换提供,Dates[Year] = 2019
计算过程筛选上下文分析
1、外部筛选器筛选器A和筛选器B中的列都来自同一张表 Dates,Auto-Exist 机制介入,两者运算的结果为 Dates 表中存在的数据组合,并以此数据构造外部筛选上下文。
外部筛选器:[AutoExist] 筛选器A × 筛选器B = 筛选器C
2、度量值内部
1)在外部筛选上下文中计算 SUMX 的迭代参数 VALUES(Dates[Year])
以筛选器 C 去筛选 Dates 表并返回 Year 列上的不重复值,得到 Dates[Year] = {2019},只有这一个值
2)迭代行上下文
SUMX 迭代 Dates[Year] = {2019},从第一行(也仅有这一行)中取得行上下文 Dates[Year] = 2019
3)在外部筛选上下文、行上下文中计算 [SumAmount] = SUM('DFact'[Amount])
[SumAmount]将行上下文转换为筛选上下文,得到 筛选器D
4) 筛选器D 覆盖外部筛选器

筛选器E 也可以写做

整个筛选器变化过程如下:

3、在最终形成的上下文中计算 SUM('DFact'[Amount]),即以 筛选器E 筛选 DFact,得到的数据集包括 2019年1、2月的数据

将该数据集中 Amount 列上的值累加,得到 2019年1、2月的 Amount 总和 1+2 = 3 。
问题描述
我们现在在 PowerBI 的报表里计算 SumxBug 得到的计算结果是 30,这与上面通过 DAX 理论得到的预期结果不符
同样 ,在 年=2020 总计行,也出现了与理论不符的结果 70。
小结
虽然官方和 sqlbi 提供了不少关于 SUMMARIZECOLUMNS函数的文章,但很少谈及其底层实现。对于总计行中的计算不符合 DAX 理论的这个疑似 bug,官网论坛对该问题的讨论大多限于理论层面,并没有得出什么结果,Marco Russo 称其为 a bug on top of another bug , 并表示“我们没有说明过这背后到底发生了什么,因为重要的是应该使用KEEPFILTER包裹迭代器中的表”。
本系列文章将探究这些现象背后究竟发生了什么,分析查询计划了解其底层计算过程,找出不符合 DAX 理论的部分,并尝试通过修补 DAX 理论以覆盖该现象(不一定能成功)。
6万+





