经常有朋友提出一个问题,然后我给出一个DAX之后,TA又不是很理解,反复多次沟通才能把一个表达式讲清楚。或者TA自己写了一个度量值,可是对输出结果无法理解:我想要的是A,为什么出来的是B?
为了帮助大家快速理解一个相对复杂的DAX,我把平时使用的方法拿出来分享如下。
为了介绍的简洁清晰,以及大部分人的可理解性,本文的DAX并不算复杂,重要的是理解的步骤和思路。(我理解的复杂DAX就是看起来比较长的、经过多层函数嵌套的、计算逻辑较难理解的表达式)
DAX都应该有一个具体的应用场景,否则分析就没有意义。
假设已有一个订单表,需要匹配每个订单的产品对应的采购成本金额;而成本表中的每种产品的采购成本是随着时间变动的,成本生效以后,该产品销售订单的成本随之变化,两个表格结构如下图,
问题看似简单,其实需要匹配几个条件,要匹配产品名称、订单日期对应的成本生效区间。转换为数据分析语言,其实就是计算该产品的小于等于订单日期的最近一个成本生效日期对应的采购成本。
在订单表上"新建列",用DAX编写如下,
单位成本 =
CALCULATE(MIN('成本表'[成本金额]),
TOPN(1, FILTER(ALL('成本表'), '成本表'[生效日期]<=
EARLIER('订单表'[订单日期])&&
'成本表'[产品名称]=EARLIER('订单表'[产品名称])),
'成本表'[生效日期] ) )
然后每笔订单对应的单位成本就被计算出来了,
当然这篇文章并不是为了匹配成本,而是理解这个DAX表达式。
对DAX熟悉的人,看到上面这个表达式并不难,但是如果是接触DAX不是很久的同学,可能并没有那么容易理解。
下面进入正题,通过以下几个步骤来快速理解上述的DAX。
一 、格式化DAX
格式化就是对DAX进行合理的换行和缩进,表面上看起来更加简洁美观,更易于阅读,其实最重要的是通过格式化可以更清晰的找出该表达式的设计逻辑和计算逻辑。
上述的表达式进行格式化处理以后,变成了这样的,是不是很清晰很多呢。
当然当你看到的DAX已经是格式化的写法,就没有必要进行这一步了。
如果是你自己编写的DAX,强烈建议从一开始就养成按格式书写的好习惯,为以后进行数据分析编写更复杂的DAX打下基础。
上面这个表达式相对简单,如果比这复杂几倍,嵌套更多层的表达式,如果不进行格式化,想看懂其结构都非常困难,更别说理解其逻辑了。
二 、对DAX从内层向外逐层分解,不理解时通过输出,来查看其计算结果。
通过上面格式化后的表达式,可以看出最内层的算是EARLIER函数,然后是FILTER函数的筛选表,之外又套了一个TOPN函数,最后由CALCULATE函数返回最终结果。
理解DAX函数的用法和逻辑,除了看关于该函数的介绍文档,最直接的就是查看该函数的计算结果,下面就以一个实例来看看该DAX每一步的输出内容。
以2月8日手机订单对应的成本为例,来理解这个表达式是如何计算出单位成本为1300的。
第1层 | EARLIER函数
EARLIER函数之前介绍过(EARLIER 函数 | PowerBI星球),比较简单,返回当前行对应的参数列,实质就是返回本行和参数列交叉的单元格。
那么EARLIER的计算结果如下,
EARLIER('订单表'[订单日期])返回:2018-2-8
EARLIER('订单表'[产品名称]返回:手机
第2层 | FILTER函数
有了第1层的结果,FILTER函数的表达式变成了,
FILTER(ALL('成本表'), '成本表'[生效日期]<= DATE(2018,2,8)&&'成本表'[产品名称]="手机")
该表达式将筛选成本表中产品名称为手机,并且生效日期早于或等于2018年2月8日的数据,通过新建表,该表达式的输出结果如下:
FILTER函数返回的正是按上述条件的筛选表。
第3层 | TOPN函数
FILTER函数的计算结果返回了早于订单日期的所有行,为了找出最近的一次生效日期,使用TOPN函数返回按生效日期排序的第1行,利用上一步的计算结果,TOPN的表达式变为,
TOPN(1,'表1','表1'[生效日期])
同样使用"新表"查看输出结果,
TOPN函数把小于订单日期的最近生效日期的所在行给筛选出来了。
第4层 | CALCULATE函数
经过TOPN的筛选,已经把成本表筛选的只剩下一行,在这一行中找采购单价已经非常简单了,表达式变为,
CALCULATE(MIN('表2'[采购单价]),'表2')
这里用了MIN函数,实际上用MAX函数也是一样的,因为只有一个值,最小值和最大值是相同的。
因为CALCULATE只能返回值,为了在表中查看输出结果,所以外面套一个{},强制把单个值变为表,结果如下:
Calculate函数得出了2月8日手机的采购成本价格1300元。
以上对几个嵌套函数的拆解,为了演示输出结果,所以生成了表1、表2、表3等三个中间表,实际上原表达式一气呵成,并不需要中间表,一次性输出最终数据。
三 、复盘总结各函数的用法
通过以上的拆解,应该能完全理解上述表达式的计算过程了,但我们不能仅理解了这个表达式,更是要通过整体的计算逻辑,能举一反三,掌握其中每个函数的用法,所以每次拆解以后,应该整体上进行复盘,思考一下表达式中主要函数的用法以及返回的结果是很必要的。
比如上述表达式中,至少可以总结出这些,
EARLIER返回当前表的当前行与参数列交叉的单元格数据;
FILTER函数根据第二个参数的筛选条件来筛选第一个参数表,返回的是一个表;
TOPN函数返回参数表中按第三个参数排序的前N行,返回的也是一个表;
CALCULATE函数返回聚合后的一个值。
经过以上的三个步骤的层层分解和复盘,不仅知道了DAX的输出结果,而且对每一个函数的计算逻辑和过程进行了全面理解。
上述DAX虽然简单,但即使是更复杂的表达式,通过以上的方式也都可以很快理解并掌握。
总结
通过以下几个步骤快速理解一个相对复杂的DAX,
1,格式化:从整体上查看其结构,为第2步打基础;
2,从内向外层层分解:必要时输出结果查看计算逻辑;
3,分解后再整体复盘:总结每一个函数和参数的用法。
本文示例文件可通过公众号回复关键字"理解DAX"获取,业务场景来自于知识星球中一个朋友的提问,来知识星球,和我一起学习PowerBI。
公众号:PowerBI星球,只有精进技能,才能无惧寒冬。
网友评论