欢迎光临散文网 会员登陆 & 注册

PowerBI之DAX神功:第2卷第1回 VAR变量

2021-08-28 16:11 作者:孙兴华zz  | 我要投稿

DAX神功第1卷我们学到了很多知识,建议大家学习DAX神功以文字版为主,多练习,视频版为辅。我这个人很懒惰,无意义的事情我从来不做。我既然担务这么多时间写文字版,恰恰证明它重要,原理课,看视频真的不是最佳选择。2020年末已有前辈用视频讲原理,但是失败了。原因在于,人脑的速度远底于语言的速度,本身原理就需要思考和理解,原理课不同于案例的讲解。

原理课的最佳学习方法是:我写文字,你阅读,你在测试过程中去理解。

一、为什么要用变量

1.代码美观,可读性更强

这个问题因人而异,就好比你喜欢一个女演员,你认为她长得很好看,但是,总会有很多人认为你眼光有问题。所以,美观和可读性是因人而异的。


2.提高性能,这才是重点

学会一门功夫以后,可以随时且多次的使用。不需要每次使用前再重新学一次吧?


情景一:张无忌不使用变量

步骤1:五年练成九阳神功

步骤2:练乾坤大挪移时需要九阳神功做钥匙:五年练成九阳神功,1天练成乾坤大挪移

步骤3:来到光明顶,已经是明教兄弟5周年祭日了

这里只是举例,在DAX函数计算上,没有这么夸张

孙兴华个人想法:数据量较大时,建议使用Pandas或SQL等,汽车改装的确可以提高速度,但是改装成本高,也不安全;你追求速度,为何不使用速度更快的交通工具呢?


情景二:张无忌使用变量

定义以下两个变量:

变量1:九阳神功=5年

变量2:乾坤大挪移=1天 因为有九阳神功做钥匙

使用:直接调用变量即可

光明顶力战六大派=九阳神功 + 乾坤大挪移

注意1.变量名不能与表同名

我个人的建议:新建列(不同表格的列除外),度量值,表名,变量名  尽量使用唯一名称,避免混淆

你不用脑子记忆哪些可以,哪些冲突,这完全是无意义的事情

一个公司的领导没有办法在招聘时不招同姓名的员工

但是,一个学校的教务处人员,他完全有能力将同姓名的学生不分在一个班级。

你现在就有能力,不将上述内容定义为重名

注意2:变量名不能使用中文

二、变量可以赋值什么类型?

《DAX神功》第1卷第7回: 证明了变量可以是一张表

一班男生 = 

        var tb1 = FILTER('Sheet1','Sheet1'[性别]="男")

return

        FILTER(tb1,'Sheet1'[班级]="一班")


《DAX神功》第1卷第17回: 证明了变量可以是一个值

占比1= 

    VAR x = sum(Sheet1[销量])

    VAR y = CALCULATE(sum(Sheet1[销量]),ALL(Sheet1))

return

    DIVIDE(x,y)

Ps:当然,这个时候使用度量值计算也可以,我们只是举例而已


网友提问:变量也可以是一个列呀,你使用过你怎么不承认呢?

《DAX神功》第1卷第14回

新建列 = 

        var x='Sheet1'[序号]

return

        sumx(FILTER('Sheet1','Sheet1'[序号]=x+1),'Sheet1'[销售日期]) 


:如果你问出这样的问题,那么你没认真听课,时间不够可以一周学一集,欲速则不达。变量等于某个列时,代表的是这个列的当前行,仍然是一个值。


三、当标题值做变量时

1.变量要按顺序引用

以VBA为例,基本所有语言都遵循这一原则

我们只是将变量a与变量b的顺序交换,结果就不同了,为什么?有小学数学基础便可理解。

VBA对没有定义的变量默认为0或空字符,但是DAX对没有定义的变量不能引用


DAX中无论新建列还是度量值情况都是这样的:

测试1 = 

    VAR a=1

    VAR   b=a+1

    VAR  c=a+b

Return

    c

2.变量在其自身的VAR/Retrun代码之外不可用 【有争议】

【新建列】毛利额1=Calculate(sumx('Sheet1','Sheet1'[销量]*'Sheet1'[售价]-'Sheet1'[销量]*'Sheet1'[进价]))

【新建列】

毛利额2 = 

    VAR x='Sheet1'[销量]*'Sheet1'[售价]

    VAR y='Sheet1'[销量]*'Sheet1'[进价]

return

    CALCULATE(sumx('Sheet1',x-y),all(Sheet1[毛利额1]))

解释:《DAX神功》第1卷第14回讲到,当新建列时,变量是某列代表当前行

Ps:因为我们在一个表中新建列时,使用了多次Calculate,会出现循环依赖,所以我们要取消【毛利额1】的筛选,详见《DAX神功》第1卷第20回 循环依赖什么鬼?

接下来我们看看度量值应该怎么写?

【度量值】毛利额3 = Sumx('Sheet1','Sheet1'[销量]*'Sheet1'[售价]-'Sheet1'[销量]*'Sheet1'[进价])

解释:Sumx创建行上下文,放到度量值中,就自动转换成筛选上下文


但是变量这样写就不行了,具体原因在《DAX神功》第1卷第14回讲过了

毛利额4 = 

    var x='Sheet1'[销量]*'Sheet1'[售价]

    var y='Sheet1'[销量]*'Sheet1'[进价]

return

    sumx('Sheet1',x-y)

解释:我们讲当前行时,讨论过这样的情况


那应该怎么写呢?

毛利额4 = 

    var x=SELECTEDVALUE('Sheet1'[销量])*SELECTEDVALUE('Sheet1'[售价])

    var y=SELECTEDVALUE('Sheet1'[销量])*SELECTEDVALUE('Sheet1'[进价])

return

    sumx('Sheet1',x-y)


但是,这样写太麻烦了,没有总计是小事,假设有十多个列四则运算怎么办?

毛利额5 = 

sumx('Sheet1',

    var x='Sheet1'[销量]*'Sheet1'[售价]

    var y='Sheet1'[销量]*'Sheet1'[进价]

return

    x-y

)

解释:将变量定义在迭代函数里面,迭代函数本身就是逐行扫描,就代表着当前行

在这个知识点上,《DAX神功》与《The Definitive Guide to DAX》推导的方式不同,《The Definitive Guide to DAX》是以嵌套的概念推导,《DAX神功》是以当前行概念推导


接下来我们再看一下毛利额6:

证明:在同一个VAR/Retrun代码块之内,定义的变量可以使用

毛利额6 = 

sumx('Sheet1',

    var x='Sheet1'[销量]*'Sheet1'[售价]

return

    x

    -

    var y='Sheet1'[销量]*'Sheet1'[进价]

return

    y

)

解释:在迭代函数,定义变量x并输出  减去  定义变量y并输出

这符合规则:在同一个VAR/Retrun代码块之内,定义的变量可以使用

有争议的地方在于:《The Definitive Guide to DAX》指出变量在其自身的VAR/Retrun代码之外不可用 

但是《The Definitive Guide to DAX》中案例举例是正确的,书中大致意思如下:

但是它的例子并不能说明,自身的VAR/Retrun代码之外不可用 

因为你并没有重新定义VAR函数



书中原文总结,定义在自身VAR/Return之外不可用,VAR/Return中声明的变量在return结束后不再可见,引用它会产生错误

关于这个问题,我在PowerBI  2021.6月版本测试通过,并没有发现不可用或引用错误:

毛利额7 = 

sumx('Sheet1',

    var x='Sheet1'[销量]*'Sheet1'[售价]

    var z=0

return

    z

    +

    var y='Sheet1'[销量]*'Sheet1'[进价]

return

    x-y

)

所以,书中说的这一点是有分歧的,拿出来与大家共同探讨,互通有无。


四、当变量做为一张表时

《DAX神功》第1卷第7回: 证明了变量可以是一张表

一班男生 = 

        var tb1 = FILTER('Sheet1','Sheet1'[性别]="男")

return

        FILTER(tb1,'Sheet1'[班级]="一班")

Ps:但这只是新建表中对表的筛选。

接下来我们讲讲在新建列或度量值中如何定义变量为表:

【新建列】

毛利额8 = CALCULATE(sumx(FILTER('Sheet1','Sheet1'[商品] in {"A","B"}),'Sheet1'[销量]*'Sheet1'[售价]-'Sheet1'[销量]*'Sheet1'[进价]))

我们现在将【毛利额8】 改写成变量形式

毛利额8 = 

        VAR tb1=FILTER('Sheet1','Sheet1'[商品] in {"A","B"})

return

        CALCULATE(sumx(tb1,'Sheet1'[销量]*'Sheet1'[售价]-'Sheet1'[销量]*'Sheet1'[进价]))

之前我们的变量是一个标量值时,它本身就是当前行,不需要筛选。

当你在新建列上使用变量是一张表时,要格外注意,因为新建列是行上下文,需要calculate转换后才可筛选。

名词解释:

惰性计算(Lazy Evaluation),又称懒惰计算、懒汉计算,是一个计算机编程中的一个概念,它的目的是要最小化计算机要做的工作。

VAR就是惰性计算:

<1> 没有被使用过的变量永远不会被计算

<2> 当变量完成了首次计算,则它不会在同一范围内被再次计算。

而这个案例,VAR tb1  只是起到了筛选表功能,并没有生效于calculate,所以得到了A和B商品毛利额总和21+24=45。 因为它首次使用时已经被计算(筛选表A和B商品),所以不会再被Calculate影响,失去了最终的筛选功能。

正确的写法:

[新建列]

毛利额8 = 

CALCULATE(

        VAR tb1=FILTER('Sheet1','Sheet1'[商品] in {"A","B"})

return

        sumx(tb1,'Sheet1'[销量]*'Sheet1'[售价]-'Sheet1'[销量]*'Sheet1'[进价])

)


不过,写成度量值时,你不需要套calculate所以不牵扯这个问题

因为度量值自动将行上下文转换成筛选上下文

【度量值】

毛利额9 = 

        VAR tb1=FILTER('Sheet1','Sheet1'[商品] in {"A","B"})

return

        sumx(tb1,'Sheet1'[销量]*'Sheet1'[售价]-'Sheet1'[销量]*'Sheet1'[进价])


五、回答网友问题:if如何用在度量值中并使用VAR变量

【1】新建列

新建列1 = if('表1'[性别]="男","先生","女士")

新建列2

    var x = '表1'[性别]

return

    IF(x="男","先生","女士")

【2】度量值

度量值1 = MINX('表1',if('表1'[性别]="男","先生","女士"))

度量值2

var x = SELECTEDVALUE('表1'[性别])

return

    IF(x="男","先生","女士")

Ps: 关于总计不显示的问题 《DAX神功》第1卷第10回 再次讲解过

友情提示:《The Definitive Guide to DAX》中关于变量的案例是有参考价值的,可以开拓你的思路。

《孙兴华讲PowerBI火力全开》PowerBI必学课程

https://www.bilibili.com/video/BV1qa4y1H7wp

《DAX神功》文字版合集:

https://www.bilibili.com/read/readlist/rl442274

《DAX神功》视频版合集:

https://www.bilibili.com/video/BV1YE411E7p3

PowerBI(DAX函数)、PowerQuery(M函数)、Python办公自动化、Python爬虫、Python数据分析、ExcelVBA、WordVBA、AccessVBA、MySQL等等

https://www.bilibili.com/read/cv10222110 


PowerBI之DAX神功:第2卷第1回 VAR变量的评论 (共 条)

分享到微博请遵守国家法律