从数据到信息
从信息到洞察

理解变量

学会使用变量对于编写 DAX 非常重要,因为变量提高了代码可读性和公式的性能

初识变量

编写 DAX 表达式时,可以通过使用变量避免重复书写相同的表达式。例如,我们来看下面这个表达式:

VAR Denominator =
SUMX ( Sales, Sales[SalesAmount] + Sales[TotalProductCost] )
VAR Numerator = SUM ( Sales[SalesAmount] )
RETURN
DIVIDE ( Numerator, Denominator )

你可以定义许多变量,它们是表达式的局部变量,也就是只对当前表达式生效,不能跨度量值使用。比如下面这种写法是错误的,原因是变量 B 只存在于度量值 1 中:

度量值 1 = VAR A=1 VAR B=2 RETURN A+B
度量值 2 = VAR C=3 RETURN B+C

和定义变量类似的还有一种 DEFINE MEASURE 的用法,在编写查询时使用,关于这两种用法详细介绍请参考 EVALUATE。

变量对于简化代码非常有用,因为避免了重复相同的子表达式。变量使用惰性计算,这意味着,如果你定义了一个变量,无论出于什么原因,如果没有被使用,那么这个变量将永远不会被计算。如果需要计算,那么计算只在首次调用时发生一次:后续对变量的调用都将读取先前计算出的值。因此,当你多次使用复杂表达式时,定义变量也可以作为优化技术使用。

正如你将在下面看到的,变量使用的是被定义时的计值上下文,不是被调用时的上下文,这个概念非常有用。

变量与计值上下文

使用变量让代码更易阅读,还可以避免多次重复相同的子表达式,但考虑到它们与计值上下文交互的方式,变量还有一个非常重要的特点,即:变量在被定义的计值上下文中计算,而不在使用它们的环境中计算,一旦变量被计算,它的值就不在变化。

当你希望在复杂公式中使用来自之前计值上下文的计算结果时,这个特性会非常有用。我们来看一个例子。假设你想用数据透视表来显示类别,并且对于每个类别,显示高销售额产品的数量。高销售额产品的定义是:一种产品的销售额超过该类别总销售额的 10%。你可以在下图看到最终效果。

透视表显示了每个类别中有多少高销售额的产品

用变量来计算这个度量值很容易,而且使用变量也让公式变得更容易阅读,如下所示:

[HighSalesProducts] :=
VAR TenPercentOfSales = [SalesAmount] * 0.1
RETURN
    COUNTROWS (
        FILTER (
            Product,
            [SalesAmount] >= TenPercentOfSales
        )
    )

这个公式的有趣之处在于,DAX 在 FILTER 迭代的外部计算变量 TenPercentOfSales。如果 TenPercentOfSales 的计算是在迭代时进行的,由于发生了上下文转换,它将计算当前迭代产品 10%的销售额,这会使得整个度量值计算错误。相反,DAX 在迭代的外部计算了变量,在内部使用它,这样就可以在当前筛选上下文之外引用表达式的值。如果你想在不使用变量的情况下写出同样的度量值,你需要这样写:

[HighSalesProductsCalculate] :=
COUNTROWS (
    FILTER (
        Product,
        [SalesAmount]
            >= CALCULATE ( [SalesAmount], ALL ( Product ), 'Product Category' ) * 0.1
    )
)

后一种代码更难读懂,因为你需要在迭代函数中重新构建出之前的计值上下文环境,这不是一项容易的任务,即使对于经验丰富的 DAX 程序员也是如此。实际上,你将会在理解筛选上下文中了解到此表达式的所有知识,在那里,我们将揭示筛选上下文的所有细节。

小测试

下面两个度量值在相同的环境中计值,它们的结果一样吗?

Measure A = CALCULATE([Total Sales],Color[Color]="White")

Measure B = VAR TotalSales = [Total Sales]
            RETURN CALCULATE(TotalSales,Color[Color]="White")
公众号二维码加载失败时的替代文字
此处内容已经被作者无情的隐藏,请输入验证码查看内容
验证码:
请关注“PowerBI极客”公众号,回复关键字“var”,获取验证码。 【注】手机扫描二维码快速关注“PowerBI极客”官方公众号。
如果你发现可以使用变量来简化计算,比如代替计值上下文中的 EARLIER,那么我们很高兴地欢迎你加入 DAX 高手的行列。如果没有,不要担心。这种情况对于第一次阅读的新人是很正常的。接下来仍有许多内容专门介绍这些复杂的知识,它们将帮助你获得掌握计值上下文所需的技能

29
说点什么

1000
 
鼓掌微笑开心憧憬爱你色并不觉得吃瓜doge二哈喵喵思考笑哭捂脸悲伤大哭抓狂汗偷笑打脸捂眼黑线问号晕拜拜闭嘴衰咒骂ok作揖
13 评论数
18 被回复的评论
14 订阅评论的人数
 
查看最近回复
查看最热评论
  订阅本文评论  
最新 最旧 得票最多
提醒
游客
hhh

l老师好!请教个问题 ,变量的,第二版 167页, 说变量是在定义的时候计值,而不是使用的时候。而173页说是:在表达式中从未使用的变量将永远不会被计算。这个要怎么理解。

成员
chen1997

老师请教您个问题,就是我要计算每个产品一段时间内去除最大值最小值每日的平均值,我构建了变量表tb,mi,ma,如图所示,最后使用,然后软件提示找不到表tb,请问我写的是哪里出了问题,正确的方式应该这么写?

8967a0bb7d50faff9afda8239f7e66f.png
成员
你猜

老师,如下图所示,YTDLY与YTD_的值相同,而我是想获得去年同期的数值。
两个值相同的原因:我想到的是在 CALCULATE (YTD_,SAMEPERIODLASTYEAR ( dim_date[日期] )) 中 YTD_已经是一个具体的数了,无法在受到Calculate的调节。不知道这个理解是否正确?

变量.png
游客
GCC

Sales Large Customers :=
VAR LargeCustomers =
FILTER (
Customer,
[Sales Amount] > 10000
)
VAR WorkingDaysIn2008 =
CALCULATETABLE (
SUMMARIZE (
‘Date’,
‘Date'[IsWorkingDay],
‘Date'[Calendar Year]
),
‘Date'[IsWorkingDay] = TRUE (),
‘Date'[Calendar Year] = “CY 2008”,
ALL ( ‘Date’ )
)
RETURN
CALCULATE (
[Sales Amount],
LargeCustomers,
KEEPFILTERS ( WorkingDaysIn2008 )
)

你好,这个在勘误上看到了,但是还是想了解一下,这个本来是想算什么呢?

成员
你猜

变量只能定义标量值,不能定义表吗?

成员
zjhred

[HighSalesProductsCalculate] :=
COUNTROWS (
FILTER (
Product,
[SalesAmount]
>= CALCULATE ( [SalesAmount], ALL ( Product ), ‘Product Category’ ) * 0.1
)
)

————————–
重新构建出之前的计值上下文环境为什么需要加上’Product Category’ ?

成员
芒果

老师好,我引用正文中的例子代码,在PBI DESKTOP里面测试建立度量值。提示有错的。截图所示的。不知道为什么。

变量错误.jpg
成员
骁龙包子

出勤(归属最后劳务) := var min_=MIN(‘频次'[最小值])
var max_=MAX(‘频次'[最大值])
RETURN
COUNTROWS(FILTER(VALUES(‘劳务明细'[姓名]),
VAR C_=
CALCULATE(DISTINCTCOUNT(‘劳务明细'[劳务出勤日期]),ALL(‘劳务明细'[劳务]))
RETURN
CALCULATE(MAX(‘劳务明细'[劳务出勤日期]),ALL(‘劳务明细'[劳务]))
=CALCULATE(MAX(‘劳务明细'[劳务出勤日期]))
&&C_>=min_&&C_<=max_))
老师这段代码使用了VAR变量嵌套,如何改写不使用VAR嵌套,来返回结果,让代码更易懂一些

成员
xuyi75

老师:小测试中,RETURN CALCULATE(TotalSales,Color[Color]=”White”),
虽然TotalSales是外部调用的变量。
但前篇中介绍过:“CALCULATE 执行上下文转换在先,应用内部筛选器在后。因此,CALCULATE 的内部筛选器可以覆盖由上下文转换创建的筛选器。”结果是ALL(Products)覆盖了前面的
这里Color[Color]=”White”是写法上的问题吗?
比如换成:RETURN CALCULATE(TotalSales,filter(product,Color[Color]=”White”),这样就只返回白色相关的销售额了吧?
注: 我不知道color这列在那个表里,所以这里用了product.

成员
136****6402

以我当前的理解能力来说我觉得小测试里的两个结果是一样的,var只是单纯的暂时存储,类似对变量赋值,return有点像是一种标识符或信号,表示我接下来要开始用变量了.

成员
ding_ye_timo

答案根据上下文的具体内容而定,不一定一样

成员
pearlzhang

小测试作答:
结果不一定一样,度量值不一样。
我理解:定义的变量是所在的筛选上下文起作用;不迭代行上下文。

DAX 圣经

导读

初识 DAX

DAX 基础知识

DAX 原理

DAX 高级原理

基础函数类型

迭代函数

CALCULATE 函数

CALCULATE 调节器

基础表函数

条件判断函数

查找匹配函数

时间智能函数

统计类函数

投影函数

分组/连接函数

集合函数

其他函数