PowerBI之DAX神功:第1卷第14回 同一表上的多层嵌套上下文EARLIER当前行与VAR变量
EARLIER 函数提取本行对应的该列的值,实际上就是提取本行和参数列交叉的单元格。返回:当前行上下文的行值
例如:第2行是当前行,那B列的当前行就是红色格子

现在我们看一下案例:表名是Shee1

需求:取下一行的销售日期
下一行日期 = sumx(FILTER('Sheet1','Sheet1'[序号]=EARLIER('Sheet1'[序号])+1),'Sheet1'[销售日期])
// 这个知识我们在《火力全开》笔记10.Earlier函数【当前行】 已经详细讲过了
但是,你要区分:下一行日期与下一个日期的区别
下一个日期 = nextday('Sheet1'[销售日期])
//《火力全开》笔记27.4,下一个日期指的是指定日期的第二天,但是与当前表中日期总数有关,《火力全开》中做过详细解释

很多网友在学习了《火力全开》第10课以后,想不通,为什么这一次的sumx不能写在度量值里面。
【新建列】下一行日期 = sumx(FILTER('Sheet1','Sheet1'[序号]=EARLIER('Sheet1'[序号])+1),'Sheet1'[销售日期])
sumx创建行上下文,它是可以放到度量值中的,但是这里,因为使用了EARLIER函数,由于当前行EARLIER函数只在行上下文中才有意义,筛选上下文中没有当前行的概念,所以并不是sumx不能放到度量值中,而是EARLIER函数不能放到度量值中。
这件事我们先放一放,我们先举个简单的例子:

《The Definitive Guide to DAX》书中有这样一节课:理解Filter、ALL和上下文交互,这里讲的东西,真的是把我整蒙圈了。
例如:有一张表,名字叫Sheet2

计算男生人数,写一个度量值:
男生人数 = countrows(FILTER('Sheet2','Sheet2'[性别]="男"))
放到矩阵中:

这个时候不显示李四是正常的,因为李四是女生,我们是通过filter将男生的表筛选出来,对男生的表统计行数,所以这里面没有李四。
当我使用切片器筛选男同学时:

当我使用切片器筛选女同学时:什么都不显示了

《The Definitive Guide to DAX》书中的解释:它有两个上下文,一个是Filter行上下文的筛选,另一个是外部切片器的筛选上下文。然后就开始不停的飙专业术语。
我发现一个问题:
假设,我现在用的尿壶(只是举例,大多数人已经不用了),我让你摸,你肯定不摸,你嫌脏。如果我是秦朝的人,两千年后有一天,你挖坑将我的尿壶挖出来了,可能你会拿它当成宝。你觉得它是古董,我觉得它只是一个旧的尿壶。
同样的道理,用大白话讲出来的东西往往不如用专业术语讲的更高大尚,无论专业术语你是否能听懂,似乎就是看专业术语没听懂也觉得自己很牛。我现学现卖,既然大家喜欢听离生活比较远的东西,那么讲原理时,我尽量少用地球上的事情来讲。

塞伯坦星球上面有两伙变形金刚,分别是霸天虎和汽车人
现在,我只看霸天虎这一部分,相当于是从塞伯坦星球上筛选出霸天虎的成员名单。
接下来,我要在霸天虎的成员名单中找擎天柱和大黄蜂。你说说看:我为什么找不到呢?

女生为什么筛选为空,不就明白了吗?

现在我们思考几个问题:
【1】我们想取Sheet2这张表中所有人员的总数:
总人数固定值=calculate(countrows('Sheet2'),all('Sheet2'))
【2】我想取Sheet2这张表男生人数的固定值:
男生人数1 = Calculate(Countrows(filter('Sheet2','Sheet2'[性别]="男")),all('Sheet2'))
【3】但是上面的公式太啰嗦,它的等效公式:
男生人数2 = Countrows(FILTER(ALL('Sheet2'),'Sheet2'[性别]="男"))

原理就是推导的过程,有必要知道它是怎么推导出来的,因为:
道生一,一生二,二生三,三生万物
你理解了道理,就学会了举一反三,但是在使用中,你不需要所有的事情都从头推一遍,我们记住了结果,就可以使用结果,如果你只背结果,思维永远得不到锻炼,这就是有些人数学考试中使用公式考出高分,但是参加工作后完全无用武之地的原因。
现在我们回归正题:如何将表Sheet1的【新建列】写成【度量值】

【新建列】下一行日期 = sumx(FILTER('Sheet1','Sheet1'[序号]=EARLIER('Sheet1'[序号])+1),'Sheet1'[销售日期])

写成度量值:
【度量值】下一行日期 = sumx(FILTER(all('Sheet1'),'Sheet1'[序号]=SELECTEDVALUE('Sheet1'[序号])+1),'Sheet1'[销售日期])
先回忆一下Selectedvalue的作用:

为什么Filter第一参数要加all?
因为新建列中的sumx是没有筛选功能的它只是创建行上下文,
但是将sumx放到度量值中就具有了筛选功能
我们现在的度量值,是要体现当前行的作用,所以要取消筛选
刚才我们已经通过公式推导了filter+all的演变过程
这是整个的推导过程,也是原理的生成过程。

《The Definitive Guide to DAX》书中将EARLIER当前行函数说的一无是处,它建议用VAR函数代替,这个问题我早在2020年6月《孙兴华讲PowerBI重制篇》中就做了讲解。没有书中说的那么夸张,你想用哪个都可以。
例如:将新建列写成VAR函数
【新建列】下一行日期 = sumx(FILTER('Sheet1','Sheet1'[序号]=EARLIER('Sheet1'[序号])+1),'Sheet1'[销售日期])
改写成:
新建列 =
var x='Sheet1'[序号]
return
sumx(FILTER('Sheet1','Sheet1'[序号]=x+1),'Sheet1'[销售日期])

我们使用VAR变量时,就相当于指定了当前行,只是隐藏了当前行函数而已。
当你将它改写成度量值时,仍然注意我们提到两个问题:
filter+all 与 selectedvalue

【度量值】
下一行日期 =
var x=SELECTEDVALUE('Sheet1'[序号])
return
sumx(FILTER(all('Sheet1'),'Sheet1'[序号]=x+1),'Sheet1'[销售日期])

不显示总计,老规矩:IF+HASONEVALUE
下一行日期 = var x=SELECTEDVALUE('Sheet1'[序号])
return
if(HASONEVALUE('Sheet1'[序号]),sumx(FILTER(all('Sheet1'),'Sheet1'[序号]=x+1),'Sheet1'[销售日期]))

《火力全开》笔记10.Earlier函数【当前行】
我们还有其它3个案例,当时只是用Earlier函数做了新建列
现在你们可以使用VAR变量做新建列,再利用filter+all 与 SELECTEDVALUE 组合做度量值
