SUMMARIZECOLUMNS 的疑似 bug(2)SUMX 在总计行

SUMX引发的思考 SUM,SUMX大概是绝大多数人学习PowerBI时先学的函数,那么我们真的了解它吗? 先来看数据模型 我们可以很容易就写出销售额的度量 销售额 = SUM( 'Sales'[SalesAmount] ) 结果很好理解,比如2020年的总计333565=82140+84122+83992+83311,同样的我们可以求出每季度在售的产品数有多少个 产品数 = DISTINCTCOUNT( 'Sales'[ProductKey] ) 这也没什么问题,那么问题来了,现在领导说在算年度总计时应该是每个季度 阅读详情

SUMX 在 SUMARIZECOLUMNS 总计行的底层计算过程

上一篇介绍了 SUMMARIZECOLUMNS 在特定情况下计算出的结果不符合 DAX 理论预测,这一篇我们开开始探究 DAX 在底层究竟是如何计算出这些结果的,主要的方法是用 DAX 查询复现该现象,通过观察物理查询计划了解底层计算步骤,试图从中定位到问题所在。


SUMMARIZECOLUMNS 的疑似 bug(1)引言
SUMMARIZECOLUMNS 的疑似 bug(2)SUMX 在总计行
SUMMARIZECOLUMNS 的疑似 bug(3)总计行是否关键点
SUMMARIZECOLUMNS 的疑似 bug(4)验证触发条件
SUMMARIZECOLUMNS 的疑似 bug(5)最终结论


现象描述

​![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fassets.b3logfile.com%2Fsiyuan%2F1690605424726%2Fassets%2Fimage-20240523100107-hhhjyfd.png%20%22sumx%20%E5%9C%A8%E6%80%BB%E8%AE%A1%E8%A1%8C%22&pos_id=img-dXDqMRhc-1716550483921)
​

红框处,2019年和2020年总计行的计算结果为:

  • 2019年的总计显示为 30,其计算的是 2019年1月、2019年2月、2020年1月、2020年2月,这4个月的 Amount 之和:1+2+13+14 = 30
  • 2020年的总计显示为 70,其计算的是 2019年11月、2019年12月、2020年11月、2020年12月,这4个月的 Amount 之和:11+12+23+24 = 70。

可以用以下 DAX 查询的结果来类比(并不是说本案例实际是这样执行的):

​image​

底层计算过程

为了弄清楚 PowerBI 在底层是怎么计算出这个结果的,需要我们深入到查询计划中去。首先提炼核心 DAX 查询代码。

PowerBI 在代码层面通过如下 DAX 查询代码计算报表中的矩阵:

DEFINE
	VAR __DS0FilterTable =  // 切片器提供
		TREATAS(
			{(2019, 1),
				(2019, 2),
				(2020, 11),
				(2020, 12)},
			'Dates'[Year],
			'Dates'[Month Num]
		)

	VAR __DS0Core = 
		SUMMARIZECOLUMNS(
			ROLLUPADDISSUBTOTAL(
                'Dates'[Year], "IsGrandTotalRowTotal", // 按年汇总,即 矩阵最下方的总计
                'Dates'[Month Num], "IsDM1Total"),  // 按月汇总,即 年 总计
			__DS0FilterTable,   // 切片器提供的筛选器
			"SumxBug", 'Measure'[SumxBug]
		)

	VAR __DS0PrimaryWindowed = 
		TOPN(
			502,
			__DS0Core,
			[IsGrandTotalRowTotal],
			0,
			'Dates'[Year],
			1,
			[IsDM1Total],
			0,
			'Dates'[Month Num],
			1
		)

EVALUATE
	__DS0PrimaryWindowed

ORDER BY
	[IsGrandTotalRowTotal] DESC, 'Dates'[Year], [IsDM1Total] DESC, 'Dates'[Month Num]

从该代码中将核心部分提出来,保持按月汇总,取消按年汇总(不是本次观察对象),得到如下的实验代码

DAX 查询

用以下 DAX 代码复现 30 和 70 的错误计算结果

EVALUATE
SUMMARIZECOLUMNS (
    'Dates'[Year],
    ROLLUPADDISSUBTOTAL ( 'Dates'[Month Num], "IsDM1Total" ),
    TREATAS (
        { ( 2019, 1 ), ( 2019, 2 ), ( 2020, 11 ), ( 2020, 12 ) },
        'Dates'[Year], 'Dates'[Month Num]
    ),
    "SumxBug", [SumxBug] 
)

运行结果中 [IsDM1Total] 为 True 、Year = 2019 和 Year = 2020 这两行,分别得到 30 和 70,符合报表计算结果。

​image​

存储引擎

Server Timings 界面记录了 4 次 Scan

​image​

存储引擎执行了 4 个 xmSQL 查询,从上往下分别是:

  • VQ1,F2V1
// xmSQL VQ1
SELECT
    'Dates'[Year],
    'Dates'[Month Num],
    SUM ( 'DFact'[Amount] )
FROM 'DFact'
    LEFT OUTER JOIN 'Dates'
        ON 'DFact'[Date]='Dates'[Date]
WHERE
    'Dates'[Month Num] IN ( 12, 1, 2, 11 ) VAND
     ( 'Dates'[Year], 'Dates'[Month Num] ) IN { ( 2020, 12 ) , ( 2019, 2 ) , ( 2020, 11 ) , ( 2019, 1 ) };

从 DFact 的扩展表中,以 Dates[Year]、Dates[Month Num] 分组计算 SUM(DFact[Amount])​,筛选条件为:

1、‘Dates’[Month Num] IN ( 12, 1, 2, 11 )

2、( ‘Dates’[Year], ‘Dates’[Month Num] ) IN { ( 2020, 12 ) , ( 2019, 2 ) , ( 2020, 11 ) , ( 2019, 1 ) }

​image​

  • VQ2,F2V0
// xmSQL VQ2
SELECT
    'Dates'[Year],
    'Dates'[Month Num]
FROM 'Dates'
WHERE
     ( 'Dates'[Year], 'Dates'[Month Num] ) IN { ( 2020, 12 ) , ( 2019, 2 ) , ( 2020, 11 ) , ( 2019, 1 ) };

从 Dates 表中,获取 Dates[Year]、Dates[Month Num] 的不重复值对,筛选条件为:

( ‘Dates’[Year], ‘Dates’[Month Num] ) IN { ( 2020, 12 ) , ( 2019, 2 ) , ( 2020, 11 ) , ( 2019, 1 ) }

​image​

  • VQ3,F1V0
// xmSQL VQ3
SELECT
    'Dates'[Year]
FROM 'Dates'
WHERE
     ( 'Dates'[Year], 'Dates'[Month Num] ) IN { ( 2020, 12 ) , ( 2019, 2 ) , ( 2020, 11 ) , ( 2019, 1 ) };

从 Dates 表中,获取 Dates[Year] 的不重复值,筛选条件与 VQ2 相同

( ‘Dates’[Year], ‘Dates’[Month Num] ) IN { ( 2020, 12 ) , ( 2019, 2 ) , ( 2020, 11 ) , ( 2019, 1 ) }

​image​

  • VQ4,F2V1
SELECT
    'Dates'[Year],
    'Dates'[Month Num],
    SUM ( 'DFact'[Amount] )
FROM 'DFact'
    LEFT OUTER JOIN 'Dates'
        ON 'DFact'[Date]='Dates'[Date]
WHERE
    'Dates'[Year] IN ( 2019, 2020 ) VAND
    'Dates'[Month Num] IN ( 12, 1, 2, 11 ) ;

与 VQ1 非常相似,从 DFact 的扩展表中,以 Dates[Year]、Dates[Month Num] 分组计算 SUM(DFact[Amount])​,筛选条件与 VQ1 有区别:

‘Dates’[Year] IN ( 2019, 2020 )

‘Dates’[Month Num] IN ( 12, 1, 2, 11 )

注意,从 VQ4 的 xmSQL 代码可以看出,WHERE 子句使用的条件,破坏了报表切片器构造的固化筛选器,该查询得到的结果中包含有 2019 年11、12月以及 2020 年1、2月的数据。

​image​

逻辑查询计划

​image​

Union: RelLogOp DependOnCols()() 0-4 RequiredCols(0, 1, 2, 3, 4)('Dates'[Year], 'Dates'[Month Num], ''[IsDM1Total], ''[SumxBug], ''[])
├── GroupSemiJoin: RelLogOp DependOnCols()() 0-3 RequiredCols(0, 1, 2, 3)('Dates'[Year], 'Dates'[Month Num], ''[IsDM1Total], ''[SumxBug])
│   ├── TreatAs: RelLogOp DependOnCols()() 0-2 RequiredCols(0, 1)('Dates'[Year], 'Dates'[Month Num])
│   │   └── TableCtor: RelLogOp DependOnCols()() 0-2 RequiredCols(0, 1, 2)(''[Value1], ''[Value2], ''[])
│   ├── Constant: ScaLogOp DependOnCols()() Boolean DominantValue=false
│   └── SumX: ScaLogOp MeasureRef=[SumxBug] DependOnCols(0, 1)('Dates'[Year], 'Dates'[Month Num]) Integer DominantValue=BLANK
│       ├── Scan_Vertipaq: RelLogOp DependOnCols(0, 1)('Dates'[Year], 'Dates'[Month Num]) 3-3 RequiredCols(0, 1, 3)('Dates'[Year], 'Dates'[Month Num], 'Dates'[Year])
│       └── Sum_Vertipaq: ScaLogOp DependOnCols(1, 3)('Dates'[Month Num], 'Dates'[Year]) Integer DominantValue=BLANK
│           ├── Scan_Vertipaq: RelLogOp DependOnCols(1, 3)('Dates'[Month Num], 'Dates'[Year]) 4-12 RequiredCols(1, 3, 6)('Dates'[Month Num], 'Dates'[Year], 'DFact'[Amount])
│           └── 'DFact'[Amount]: ScaLogOp DependOnCols(6)('DFact'[Amount]) Integer DominantValue=NONE
└── GroupSemiJoin: RelLogOp DependOnCols()() 0-3 RequiredCols(0, 1, 2, 3)('Dates'[Year], 'Dates'[Month Num], ''[IsDM1Total], ''[SumxBug])
    ├── TreatAs: RelLogOp DependOnCols()() 0-2 RequiredCols(0, 1)('Dates'[Year], 'Dates'[Month Num])
    │   └── TableCtor: RelLogOp DependOnCols()() 0-2 RequiredCols(0, 1, 2)(''[Value1], ''[Value2], ''[])
    ├── Constant: ScaLogOp DependOnCols()() Boolean DominantValue=true
    └── SumX: ScaLogOp MeasureRef=[SumxBug] DependOnCols(0)('Dates'[Year]) Integer DominantValue=BLANK
        ├── Scan_Vertipaq: RelLogOp DependOnCols(0)('Dates'[Year]) 3-3 RequiredCols(0, 3)('Dates'[Year], 'Dates'[Year])
        └── Sum_Vertipaq: ScaLogOp DependOnCols(0, 3)('Dates'[Year], 'Dates'[Year]) Integer DominantValue=BLANK
            ├── Scan_Vertipaq: RelLogOp DependOnCols(0, 3)('Dates'[Year], 'Dates'[Year]) 4-12 RequiredCols(0, 3, 6)('Dates'[Year], 'Dates'[Year], 'DFact'[Amount])
            └── 'DFact'[Amount]: ScaLogOp DependOnCols(6)('DFact'[Amount]) Integer DominantValue=NONE

逻辑结构图:

请添加图片描述

从逻辑查询计划来看,DAX 底层认为该计算可以由两部分通过 Union 合并而成:

  • Union 左边分支,从 Line 7 的代码可以看出,这部分计算 Date[Year]、Date[Month Num] 分组下的 SUM(DFact[Amount])​,这正是各个非总计行
  • Union 右边分支,从 Line 16 的代码可以看出,这部分计算 Date[Year] 分组下的 SUM(DFact[Amount])​,这正是两个总计行

物理查询计划

​image​

Union: IterPhyOp LogOp=Union IterCols(0, 1, 2, 3, 4)('Dates'[Year], 'Dates'[Month Num], ''[IsDM1Total], ''[SumxBug], ''[])
├── GroupSemijoin: IterPhyOp LogOp=GroupSemiJoin IterCols(0, 1, 2, 3)('Dates'[Year], 'Dates'[Month Num], ''[IsDM1Total], ''[SumxBug])
│   └── CrossApply: IterPhyOp LogOp=SumX IterCols(0, 1)('Dates'[Year], 'Dates'[Month Num])
│       ├── Spool_UniqueHashLookup: IterPhyOp LogOp=TreatAs LookupCols(0, 1)('Dates'[Year], 'Dates'[Month Num]) #Records=4 #KeyCols=2 #ValueCols=0
│       │   └── AggregationSpool<GroupBy>: SpoolPhyOp #Records=4
│       │       └── TreatAs: IterPhyOp LogOp=TreatAs IterCols(0, 1)('Dates'[Year], 'Dates'[Month Num])
│       │           └── TableCtor: IterPhyOp LogOp=TableCtor IterCols(0, 1, 2)(''[Value1], ''[Value2], ''[])
│       └── Spool_Iterator<SpoolIterator>: IterPhyOp LogOp=SumX IterCols(0, 1)('Dates'[Year], 'Dates'[Month Num]) #Records=4 #KeyCols=2 #ValueCols=1
│           └── AggregationSpool<Sum>: SpoolPhyOp #Records=4
│               └── CrossApply: IterPhyOp LogOp=Sum_Vertipaq IterCols(1, 3)('Dates'[Month Num], 'Dates'[Year])
│                   ├── Spool_MultiValuedHashLookup: IterPhyOp LogOp=Scan_Vertipaq LookupCols(1, 3)('Dates'[Month Num], 'Dates'[Year]) IterCols(0)('Dates'[Year]) #Records=4 #KeyCols=10 #ValueCols=0
│                   │   └── ProjectionSpool<ProjectFusion<>>: SpoolPhyOp #Records=4
│                   │       └── Cache: IterPhyOp #FieldCols=2 #ValueCols=0
│                   │           └── Spool_Iterator<SpoolIterator>: IterPhyOp LogOp=TreatAs IterCols(0, 1)('Dates'[Year], 'Dates'[Month Num]) #Records=4 #KeyCols=2 #ValueCols=0
│                   │               └── AggregationSpool<GroupBy>: SpoolPhyOp #Records=4
│                   │                   └── TreatAs: IterPhyOp LogOp=TreatAs IterCols(0, 1)('Dates'[Year], 'Dates'[Month Num])
│                   │                       └── TableCtor: IterPhyOp LogOp=TableCtor IterCols(0, 1, 2)(''[Value1], ''[Value2], ''[])
│                   └── Spool_Iterator<SpoolIterator>: IterPhyOp LogOp=Sum_Vertipaq IterCols(1, 3)('Dates'[Month Num], 'Dates'[Year]) #Records=4 #KeyCols=10 #ValueCols=1
│                       └── ProjectionSpool<ProjectFusion<Copy>>: SpoolPhyOp #Records=4
│                           └── Cache: IterPhyOp #FieldCols=2 #ValueCols=1
│                               └── Spool_Iterator<SpoolIterator>: IterPhyOp LogOp=TreatAs IterCols(0, 1)('Dates'[Year], 'Dates'[Month Num]) #Records=4 #KeyCols=2 #ValueCols=0
│                                   └── AggregationSpool<GroupBy>: SpoolPhyOp #Records=4
│                                       └── TreatAs: IterPhyOp LogOp=TreatAs IterCols(0, 1)('Dates'[Year], 'Dates'[Month Num])
│                                           └── TableCtor: IterPhyOp LogOp=TableCtor IterCols(0, 1, 2)(''[Value1], ''[Value2], ''[])
└── GroupSemijoin: IterPhyOp LogOp=GroupSemiJoin IterCols(0, 1, 2, 3)('Dates'[Year], 'Dates'[Month Num], ''[IsDM1Total], ''[SumxBug])
    └── Spool_Iterator<SpoolIterator>: IterPhyOp LogOp=SumX IterCols(0)('Dates'[Year]) #Records=2 #KeyCols=1 #ValueCols=1
        └── AggregationSpool<Sum>: SpoolPhyOp #Records=2
            └── Spool_Iterator<SpoolIterator>: IterPhyOp LogOp=Sum_Vertipaq IterCols(0, 3)('Dates'[Year], 'Dates'[Year]) #Records=4 #KeyCols=2 #ValueCols=1
                └── AggregationSpool<AggFusion<Sum>>: SpoolPhyOp #Records=4
                    └── CrossApply: IterPhyOp LogOp=Sum_Vertipaq IterCols(0, 3)('Dates'[Year], 'Dates'[Year])
                        ├── Spool_MultiValuedHashLookup: IterPhyOp LogOp=TreatAs LookupCols(1)('Dates'[Month Num]) IterCols(0)('Dates'[Year]) #Records=4 #KeyCols=2 #ValueCols=0
                        │   └── AggregationSpool<GroupBy>: SpoolPhyOp #Records=4
                        │       └── TreatAs: IterPhyOp LogOp=TreatAs IterCols(0, 1)('Dates'[Year], 'Dates'[Month Num])
                        │           └── TableCtor: IterPhyOp LogOp=TableCtor IterCols(0, 1, 2)(''[Value1], ''[Value2], ''[])
                        └── Cache: IterPhyOp #FieldCols=2 #ValueCols=1
                            ├── Spool_Iterator<SpoolIterator>: IterPhyOp LogOp=TreatAs IterCols(0, 1)('Dates'[Year], 'Dates'[Month Num]) #Records=4 #KeyCols=2 #ValueCols=0
                            │   └── AggregationSpool<GroupBy>: SpoolPhyOp #Records=4
                            │       └── TreatAs: IterPhyOp LogOp=TreatAs IterCols(0, 1)('Dates'[Year], 'Dates'[Month Num])
                            │           └── TableCtor: IterPhyOp LogOp=TableCtor IterCols(0, 1, 2)(''[Value1], ''[Value2], ''[])
                            └── Spool_Iterator<SpoolIterator>: IterPhyOp LogOp=Scan_Vertipaq IterCols(0, 3)('Dates'[Year], 'Dates'[Year]) #Records=2 #KeyCols=10 #ValueCols=0
                                └── ProjectionSpool<ProjectFusion<>>: SpoolPhyOp #Records=2
                                    └── Cache: IterPhyOp #FieldCols=1 #ValueCols=0
                                        └── Spool_Iterator<SpoolIterator>: IterPhyOp LogOp=TreatAs IterCols(0, 1)('Dates'[Year], 'Dates'[Month Num]) #Records=4 #KeyCols=2 #ValueCols=0
                                            └── AggregationSpool<GroupBy>: SpoolPhyOp #Records=4
                                                └── TreatAs: IterPhyOp LogOp=TreatAs IterCols(0, 1)('Dates'[Year], 'Dates'[Month Num])
                                                    └── TableCtor: IterPhyOp LogOp=TableCtor IterCols(0, 1, 2)(''[Value1], ''[Value2], ''[])

完整的流程结构图如下:

在这里插入图片描述

这个案例的物理查询计划同逻辑查询计划的流程结构相似,也是将整个计算区分成总计行和非总计行的计算最后再合并起来,简化表达为如下流程:

在这里插入图片描述

实际计算过程

仔细阅读物理查询计划后,对计算过程有了一定的了解,我把整体流程数据流大致演示一下(省略了几个分组的操作,对理解本案例并没有影响):

​底层计算过程模拟截图​

(在 DAX 底层计算过程中,经常能看到一些步骤通过合并查询,切换来自不同源的同一列,这些不同来源的列通过列后面的数字来标识,比如 Year(0),可能来自 TreatAS,而 Year(3) 则来自 VQ4,相同来源的列可以通过 Lookup 操作符进行匹配,不同来源的列则要通过 HashLookup 来匹配。 )

30 和 70 这两个计算结果由右侧【计算总计行】分支产生,需要重点理解下该部分的计算过程。

1、该分支从 VQ4 查询开始,前面讲过了,该数据缓存中包含有切片器未选择的 2019年11、12月 和 2020年1、2月相关数据。

2、中间的步骤是在切换 Year(3) 到 Year(0) ,Year(3) 来自 VQ4,Year(0)来自 TreatAs,具体的做法是将 VQ4 与 TreatAs 表构造器{ ( 2019, 1 ), ( 2019, 2 ), ( 2020, 11 ), ( 2020, 12 ) } ​通过 [Month Num] 列进行匹配,比如 VQ4 中的 2020年1月 ,通过 [Month Num] = 1,从 TreatAs 中匹配到 Year(0)=2019,于是出现了红框这行数据

​image​

3、按 Year(0) 进行分组汇总,于是在 Year(0) = 2019 组内,实际包含的是 2019年1、2月 和 2020年1、2月的数据,最后的计算结果是 1+2+13+14 = 30

​image​

‍

问题分析

通过上述分析,可以了解到如下情况:

  1. SUMMARIZECOLUMNS 分别计算总计行和非总计行,最后合并起来得到最终结果
  2. VQ4 中的 WHERE 子句使用的 Dates[Year] And Dates[Month Num] ,破坏了切片器构成的固化筛选器,导致查询结果中不仅有 2019年1、2月,2022年11、12月,还包含了 2019年11、12月、2020年1月、2月
  3. 底层计算时按照固化筛选器中的 [Month Num] 去匹配 [Year] ,导致最后分组计算时,在2019年分组下包含有 2020年的数据。

由此可知,VQ4 WHERE 子句Dates[Year] IN ( 2019, 2020 ) VAND Dates[Month Num] IN ( 12, 1, 2, 11 ) ​ 破坏了 TREATAS ({ ( 2019, 1 ), ( 2019, 2 ), ( 2020, 11 ), ( 2020, 12 ) },'Dates'[Year], 'Dates'[Month Num]))​ 构造的固化筛选器,是导致总计行计算错误的关键原因。

DAX 底层并不会像 DAX 理论那样逐步去分析计算各个筛选上下文之间的关系,而是直接根据代码得出它需要使用的 xmSQL 数据再进行后续处理。DAX 理论是用来指导用户让用户可以预测出于代码的预测结果,应当与 DAX 底层计算结果保持一致。

显然在本案例中,DAX 理论与实际计算结果无法保持一致且无法调和,DAX 理论无法解释 DAX 底层为什么会使用 VQ4 这样的数据去计算本案例中的 DAX 查询代码。

为了定位问题发生的根源,做一些猜测,然后设计实验排查,希望运气够好能够早点定位到关键因素:

  1. SUMMARIZECOLUMNS 与 迭代器 的配合,本案例中,尤其是在计算总计行时
  2. SUMMARIZECOLUMNS 中 参数作用于参数表的方式
  3. …待补充

‍

实验设计

猜想1好验证,从报表中把 [Month Num] 去掉,直接在 [Year] 这个维度上进行计算,看看没有了总计行那部分的计算,结果会不会有所不同。

猜想2不好验证,需要观察更多的数据计算表现,搜集更多信息

那就在下一篇中来验证猜想1吧。

PowerBI之DAX实战:从聚合、统计到表操作与关系函数的场景化应用 本文深入探讨了PowerBI中DAX函数的实战应用,从基础的聚合与统计函数(如SUMX、RANKX)到高级的表操作函数(如SUMMARIZECOLUMNS、ADDCOLUMNS)与关系函数(如RELATED、TREATAS),通过电商数据分析场景,系统讲解了如何构建动态计算指标与交互式仪表盘,是掌握PowerBI核心分析能力的关键指南。 阅读详情

相关推荐

2.23 PowerBI数据建模-动态累计求和的实战应用

本文深入探讨了PowerBI数据建模中动态累计求和的实战应用,通过具体案例和DAX代码示例,展示了如何实现单维度和多维度的动态累计计算。文章详细解析了动态累计求和在帕累托分析、进度监控等商业场景中的核心价值,并提供了性能优化技巧和典型业务场景的应用案例,帮助用户提升数据分析效率。

weixin_28731223的博客 372

power bi求和错误

https://www.jianshu.com/p/2eeb3092ab18

weixin_42578783的博客 1296

Power BI中SUMMARIZE函数核心原理与企业级实战指南

SUMMARIZE是DAX中关键的表构造函数,用于在内存中动态生成分组汇总表,其本质并非聚合而是可控的虚拟物化——先按指定列分组,再通过ADDCOLUMNS等函数注入计算逻辑。它天然支持行上下文与筛选上下文协同,在RFM客户分层、销售漏斗分析、预算偏差对比等多维建模场景中不可替代。相比SUMMARIZECOLUMNS,它具备更强的上下文稳定性与调试友好性;相比GROUPBY,它支持非聚合字段直接输出,灵活性更高。掌握分组列处理、CURRENTGROUP()上下文穿透及预筛选优化,是提升Power BI复杂度

weixin_29040367的博客 256

SUMMARIZE函数解决之前的总计错误

小伙伴们,还记得之前的总计栏显示错误问题么? 本期呢,白茶决定来研究解决这个问题,先来看看之前的样例。 放上之前的每笔成交代码: 每笔成交花费 = VAR CQ = [每一笔消费达成日期] VAR DQ = IF ( SUM ( Sheet1[销售额] ) > 0, CALCULATE ( [每一笔消费达成日期], FILTER ( ALL ( Sheet1[日期] ), .

Fabric丨白茶 2016

别再死记硬背DAX函数了!用这3个真实业务场景(销售分析/客户分层/动态排名)彻底搞懂PowerBI表操作

本文通过销售分析、客户分层和动态排名三个真实业务场景,深入解析PowerBI中DAX表操作函数的实战应用。重点介绍SUMMARIZECOLUMNS、VALUES和RANKX等核心函数的高效使用技巧,帮助数据分析师摆脱死记硬背,掌握灵活解决业务问题的能力,提升报表自动化水平。

weixin_42531710的博客 365

SUMMARIZECOLUMNS 的疑似 bug(1)引言

与 Excel 通过 MDX 创建报表的方式不同,PowerBI 在代码层面主要是通过 SUMMARIZECOLUMNS​ 函数计算报表中各个视觉对象,它实现了 MDX 中的 auto-exist 功能并具有诸多特性,能够在许多场景中代替ADDCOLUMNS​+ SUMMARIZE​的应用。在特定情况下,SUMMARIZECOLUMNS ​的计算结果似乎并不符合 DAX 理论,本篇介绍这些疑似存在 BUG 的现象。

一棵松的博客 1382

Power BI中summarizecolumns函数、sum函数实现SQL Server中的group by分组汇总

Power BI是微软开发的一款功能非常强大的的BI工具,可以制作非常美观的报表,但这个工具的核心是DAX,翻译为中文就是 数据分析表达式,有点类似于excel函数,但又很不一样。 DAX中的很多功能可以与SQL对应,但差异也很大。   下载Power BI 以及 输入实验数据,请参考前一篇文章: Power BI中selectcolumns函数+related函数实现SQL Server中...

SQL Server探索 1万+

DAX 底层计算过程演示——ADDCOLUMNS + 复杂上下文环境

关于 DAX 理论的资料很多,DAX 理论帮助我们理解和预测 DAX 的计算结果,但 DAX 在底层实际是怎么计算的却少有人谈及。本篇以一段在复杂上下文环境中通过 ADDCOLUMNS 进行计算的 DAX 查询代码为观察对象,使用 DAX Stuido 查看查询计划,展示其在存储引擎中执行了哪些数据查询,揭示公式引擎如何组装这些数据最终得出计算结果。

一棵松的博客 2071

Power BI基础操作-SUMMARIZECOLUMNS()函数

软件打开及数据导入 打开软件之后要求登录账号或者免费试用,这时直接点击右上角叉号即可。 点击“获取数据”,选择相应的数据类型。点击“加载”。 创建新数据集 点击“输入数据”。 添加完成后,点击“加载”即可。 SUMMARIZECOLUMNS()函数 函数作用:分组聚合 语法:SUMMARIZECOLUMNS(第1参数,第2参数,第3参数,第4参数) 位置 参数 描述 第1参数 GroupBy_ColumnName 分组依据,可重复,可用于小计和总计函数 第2参数 Filt.

m0_46305747的博客 9911

实战指南:如何用DCCRN模型提升语音增强效果(附代码示例)

本文提供了基于DCCRN模型进行语音增强的实战指南。通过深入解析复数网络如何协同处理语音的幅度与相位信息,并附有完整的PyTorch代码实现,帮助开发者从数据准备、模型搭建到训练调优,构建高效的实时语音增强系统,有效提升嘈杂环境下的语音清晰度。

weixin_29054245的博客 479

Centos7.6操作系统安装+Bond配置(600GB磁盘版本)

1.安装前准备工作 准备centos7.6操作系统镜像 CentOS-7-x86_64-DVD-1810.iso 服务器安装一般都是在BMC界面操作,所以安装前需要在BMC界面挂载好操作系统镜像 重启服务器后自动进入安装界面。 华为大数据集群安装操作系统配置

小时光 6010

SUMMARIZECOLUMNS 的疑似 bug(4)验证触发条件

上一篇发现总计行并不是关键点,并根据观察到的现象猜测了3个关键点,本篇通过单变量控制实验逐一对其进行验证,判断哪些条件会触发计算结果与 DAX 理论不符的情况,并最终确认了这些条件。

一棵松的博客 799

手把手教你用Chrome DevTools逆向分析抖音a_bogus参数(附完整日志插桩方法)

本文详细介绍了如何使用Chrome DevTools逆向分析抖音a_bogus参数的生成逻辑,包括XHR断点定位、日志插桩追踪和加密核心逻辑解析。通过实战案例,帮助开发者掌握逆向工程技巧,应对抖音接口的动态加密变化,特别适合研究dy接口和a_bogus参数的技术人员。

weixin_27741699的博客 787

SUMMARIZECOLUMNS 的疑似 bug(3)总计行是否关键点

上一篇介绍了在总计行中出现与理论预期不符的结果,通过物理查询计划了解其底层计算过程,猜想是否 `SUMMARIZECOLUMNS`​函数对总计行的计算存在什么特殊算法,本篇验证在非总计行中进行计算的情况,以帮助判断总计行是否是关键点。

一棵松的博客 1087

ADRV9009学习资料保存:基于XC7Z100+ADRV9009的双收双发无线电射频板卡

ADRV9009学习资料保存:基于XC7Z100+ADRV9009的双收双发无线电射频板卡 一、板卡概述 基于XC7Z100+ADRV9009的双收双发无线电射频板卡是基于XilinxZYNQFPGA和ADI的无线收发芯片ADRV9009开发的专用功能板卡,用于5G小基站,无线图传,数据收发...

9367

硬件工程师入门进阶,一文搞懂,看这篇就对了

每家公司的datasheet都有严格的规范,及独特的风格,有时候还会穿插一些原理性的介绍,比如ADI公司的一些ADC/DAC器件资料里面,还会包含AD/DA转换的原理性讲解内容,Datasheet既可以是我们设计上的好帮手,也是学习的好资料。在出货量大的产品中,尽量减少物料种类,比如开头说的,1%的电阻不得不用,那么5%的替换成1%的,物料种类就减少一种,量就大了,能不能争取更优的价格呢?如果说前面学的是内功,那这一关,是招式、是工具的使用,原理图和PCB设计都有对应的工具,教程也很多,且比较容易上手。

一路带飞的博客 5万+

SUMMARIZECOLUMNS 的疑似 bug(5)最终结论

上一篇找到了触发 `SUMMARIZECOLUMNS`​ 计算的结果不符合 DAX 理论的充分条件,这一篇尝试探讨修正理论对其进行解释,在这一篇中,我以为找到了一个合理的理论假设,但随后一个新的发现给了我当头一棒,这一篇应该是本系列的最后一篇,我必须直面现实了。

一棵松的博客 1560

Agisoft Metashape相机标定笔记

使用Metashape进行自动相机标定是可能的。(可选:使用打印的棋盘格图案,但需保证它是平坦的且单元格是正方形)。相机标定步骤支持全相机标定矩阵的估计,包含非线性的畸变参数。相机模型的细节请参照附录D——相机模型板块。:在通用的工作流程中,相机标定步骤可以跳过。因为Metashape会在图像定向过程中进行相机自标定。但是,如果定向结果不稳定,例如,由于影像之间缺乏连接点,额外进行单独的相机标定步骤也许是有用的。

天桥飞熊的博客 3975

DAX:翻译《介绍SUMMARIZECOLUMNS》

原文:Introducing SUMMARIZECOLUMNS 建议用SUMMARIZECOLUMNS来代替SUMMARIZE函数,和ADDCOLUMNS/SUMMARIZE的组合。下面两个DAX的结果是一样的: Sales by Year and Color new style = SUMMARIZECOLUMNS ( 'Date'[Calendar Year], 'Prod...

悦光阴的博客 619

LiveReload:释放你的F5,实时预览HTML效果

一、liveReload插件开发背景Web前端开发人员在写页面时,如果修改了HTML or CSS,要想看效果通常的做法就是保存代码就得 Alt+Tab,切换到浏览器(当然,我知道很多开发人员是双屏操作不一定需要切换到浏览器),但是一定要F5刷新才能看自己刚写的代码有没有效果,没有效果就再切换到编辑器下修改,然后再切换到浏览器F5刷新看效果,还没有效果,就再继续修改,如此反复。时间久了,前端自动化...

Char_n的博客 2510

SAP Joule 经过了超过 2.5 亿行 ABAP 代码的训练之后......

披露的统计数据,Joule 提供的这种全新系统交互方式,可将事务性任务执行速度提高 90%,访问 SAP Help Portal 内容的速度提高 95%。在 ABAP 应用开发领域,SAP 官网数据显示,Joule 经过超过 2.5 亿行 ABAP 代码的训练,有信心成为这一领域行业领先的代码助手。刚刚过去的 SAP 蓝宝石大会上,SAP 提到,从2023年第四季度以来,SAP 已经交付了 50 项基于人工智能的创新。让其生成 SAP 应用能够识别的结构化应用数据,业务用户全程无需离开 SAP 应用程序。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 798

6.13 PowerBI系列之DAX函数专题-summarize,rollup和summarizecolumns以及groupby

summarizecolumns(一个query)>summarize>(两个query语句)>groupby(复杂一些),powerbi视觉对象后台生成的DAX表达式也是默认使用summarizecolumns。filter(‘sales’,‘sales’[产品类别]=“配件”),5.rollup做小计在summarize中使用。4.分组函数中的列可以来自模型中的不同表;sum(‘sales’[订单金额])) //只取配件的汇总 (图4)‘sales’[产品子类别],‘sales’[产品类别],

qq_33842426的博客 2020

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

PowerBI之DAX 2:聚合、统计、关系、表操作函数

SUM是DAX中最常用的聚合函数,它只有一个参数:<column>销售总额 = SUM( '订单表'[销售额] )<table>:将要进行计算的表,可以是FILTER表表达式计算得到的筛选表:对表中每一行进行计算的表达式所以SUMX返回的就是:对表的每一行按表达式进行计算,再进行求和。销售总额 =SUMX( '订单表','订单表'[销售额] )由于SUM函数只有一个参数,决定了它只能处理一个表的一列的求和,而涉及到多列/多表的计算,或者对特定表达式的求和,它就不适用了。

qq_56591814的博客 4336

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

2.26 PowerBI数据建模-排名前三的人名及销量(SUMMERIZECOLUMNS+CONCATENATEX)

给上下文中的人员配上一列排名形成一个VAR过程表,取这个表中排名小于等于3的人名列,每一行的值用CONCATENATEX合并到一起,用逗号隔开,按销量降序,遇到销量相同,用人员升序。像上一个度量值做出VAR过程表后,筛选排名小于等3的行,对销量列求和(此处VAR表中没有销量列,筛选上下文传递到了销量表)。有如下一张销售表,写一个度量值,提取销售前三名人员的名字,用逗号隔开,按照销量降序排列,遇到并列,用人名升序排列。人员按销量排名,此处为随上下文变化的动态排名,用的ALLSELECTED。

PowerBI自己学 618

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Power BI DAX性能优化:5个导致报表卡顿的致命写法

DAX是Power BI的核心计算语言,其执行效率直接受VertiPaq列式引擎特性影响。理解布尔筛选、临时表物化、迭代器开销等底层原理,是实现高性能报表的关键技术基础。当DAX公式触发FILTER隐式建表、SUMX无节制迭代、RELATED长链跳转、ALL引发上下文爆炸或ISINSCOPE高频判断时,会严重破坏位图索引与向量化执行路径,导致加载延迟激增。这些模式在真实生产环境(如零售销售仪表板、电商GMV看板)中高频出现,常表现为10秒级以上响应延迟。本文聚焦可立即落地的工程化修复方案,覆盖CALCULA

duiker 485
上一篇: SUMMARIZECOLUMNS 的疑似 bug(1)引言
下一篇: SUMMARIZECOLUMNS 的疑似 bug(3)总计行是否关键点
apinerand
博客等级 码龄9年 201粉丝 11原创
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值