SUMMARIZECOLUMNS 的疑似 bug(1)引言


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

案例文件 下载
image

报表环境

数据表

  • DFact, 包含两列:DateAmount

image

  • Dates,日期表,包含 Date, Year, Month Num, Month, YM 5 列

表间关系

Dates 1 — * DFact,以 [Date] 关联 Dates 和 DFact,Dates 为一端,DFact 为多端

image

度量值

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] 为值

image

理论预期

按照 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]))

image

  • 报表行标题提供筛选器B,在 Year = 2019 总计行Dates[Year] = 2019

image

两个筛选器中把 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

image

4) 筛选器D 覆盖外部筛选器
在这里插入图片描述
筛选器E 也可以写做
在这里插入图片描述
整个筛选器变化过程如下:
在这里插入图片描述
​3、在最终形成的上下文中计算 SUM('DFact'[Amount])​,即以 筛选器E 筛选 DFact,得到的数据集包括 2019年1、2月的数据
在这里插入图片描述
将该数据集中 Amount 列上的值累加,得到 2019年1、2月的 Amount 总和 1+2 = 3 。

问题描述

我们现在在 PowerBI 的报表里计算 SumxBug 得到的计算结果是 30,这与上面通过 DAX 理论得到的预期结果不符
image

同样 ,在 年=2020 总计行,也出现了与理论不符的结果 70。

小结

虽然官方和 sqlbi 提供了不少关于 SUMMARIZECOLUMNS​函数的文章,但很少谈及其底层实现。对于总计行中的计算不符合 DAX 理论的这个疑似 bug,官网论坛对该问题的讨论大多限于理论层面,并没有得出什么结果,Marco Russo 称其为 a bug on top of another bug , 并表示“我们没有说明过这背后到底发生了什么,因为重要的是应该使用KEEPFILTER​包裹迭代器中的表”。

image

本系列文章将探究这些现象背后究竟发生了什么,分析查询计划了解其底层计算过程,找出不符合 DAX 理论的部分,并尝试通过修补 DAX 理论以覆盖该现象(不一定能成功)。

评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值