VAR 变量语法运用(5)
1、变量作为DAX的筛选
先来回顾一下:
(1)你应该还记得,我们在前面的讨论中说到:变量能构建DAX的外部筛选器。这可能是书写DAX 最需要的一个功能。比如,我们讨论过的,使用变量可以摆脱EARLIER函数的约束。而EARLIER可能是 DAX学习 中必须要迈过去的一道坎。
如果将变量理解为:存在于外部筛选器里被公式引用的计算。那么,它的含义更像是OUTER --“外部的”,而不是EARLIER --“更早的”:
Product[ListPriceRankDense] =
VAR CurrentPrice = Product[Unit Price]
RETURN
COUNTROWS (
FILTER (VALUES ( Product[Unit Price] ),
Product[Unit Price] > CurrentPrice ) ) + 1
即便在这个表达式中,你也可以将这里的变量CurrentPrice理解为:它是在筛选器外部单独计算的。因此,意思很明显,它先评估当前 Product[Unit Price]--产品的价格(将该列保存为存储数据),而后在 FILTER筛选器里面引用它,这时候它已经是一个按定义得出的结果值。所以,在此表达式中不再需要EARLIER。
(2)变量使得复杂子表达式能被单个计算式替代,只要存在需要多次计算的相同子表达式时,使用变量定义该计算式来作为DAX 优化器,从而保证计算只发生一次,以产生更快的代码。
(3)通过前面两点的复习,第一,变量能构建筛选器(尽管是外部的),第二,能使用一个变量替代同一表达式的重复引用。我们回忆一下DAX的两个重要的概念:筛选+计算。变量能虚拟出需要的行或列筛选,也就是说,每当DAX中需要一个列表筛选时,你就定义一个列表变量指代它,同样,需要一个“当前行”行筛选时,你就定义一个变量来指代它……。依次类推,直到需要的所有筛选列表都具备时,再将它们 RETURN 取出来组装成DAX的筛选。这有利于DAX的步骤思考以及按逻辑简化公式的复杂过程。这就是我们前面所说的:
使用变量的最重要的原因是能按步骤书写DAX公式,以及提高公式的可读性。 为DAX计算的一些中间步骤提供一个变量名称,这是编写DAX 代码的很好的方法。
2、补充与注意事项
虽然变量存在诸多方面的好处,但使用中也需要注意几个方面,这在前面也有一点提示(某些情况下不能使用变量---比如需要回到原数据列表的计算式)。
(1)补充:VAR在EVALUATE中的应用(DAX Studio等取出数据的方式)
可以在EVALUATE语句中定义变量,其语法与用于变量定义的标准语法略有不同。我们已经知道,通常使用VAR来定义一个变量,再由RETURN返回后的表达式访问先前定义的该变量。这样的标准语法,可以替换DAX中的任何标量值或表表达式。
但是,当编写EVALUATE语句时,也是在定义部分中定义一个变量,但不必在之后写入RETURN:
DEFINE
VAR ExpensiveProducts = FILTER ( Product, Product[Unit Price]> 3000 )
EVALUATE
CALCULATETABLE ( Product, ExpensiveProducts )
因此,EVALUATE的一个更完整的带变量的语法定义如下:
在任何情况下,只有在EVALUATE之后的表表达式中使用变量时,才会对该变量进行计值,并且计值不依赖于变量定义之后进行的当前筛选操作。换句话说,可以在EVALUATE之后使用VAR / RETURN标准变量语法。
这不难理解:EVALUATE是直接从数据模型里查询数据(先有压缩数据再有存储数据),变量是存储数据,同时也是数据模型的一部分。因此,EVALUATE能置于RETURN的前面用以取出变量数据,反之,则不行)。如下例所示:
EVALUATE
VAR ExpensiveProducts = FILTER ( Product, Product[Unit Price] > 3000 )
RETURN
CALCULATETABLE ( Product, ExpensiveProducts )
(2)变量的惰性
一方面,变量的使用会带来更有效的公式执行,是因为变量减少了公式引擎和原数据之间的“往返”(比如遍历、迭代列表。然而,变量能直接被公式引擎引用,即只需请求一次计算)。而且,变量能作为计算式的公用筛选器。
另一方面,不仅在计算式中使用变量,如果在 DAX 中查询数据模型(筛选),也应考虑使用变量来简化代码。比如,当需要使用多个计算语句来获取多个结果子集时,还应考虑哪些变量可以在多个查询中被使用…..。
值得提醒的是,无论是以上两个情况的哪一种,在一个或多个计算语句之前,某个定义语句只能出现一次:一个变量可以在一个计算式被反复引用,但一个变量不能存在于多个不同的计算式里(比如在一个度量里的变量,不能用于另外一个度量(其实根本就不会出现),或者在一个计算中,RETURN之后如果还需要引用该变量,则需要重新定义。即变量只存在于当前定义下的计算式中)
我们通过几个DAX表达式来加深理解:
下图中,我们定义了两个在计算式中使用的变量:Date01与Date03,当在RETURN之后的计算式里使用它们时,智能提示里会出现刚刚定义的这两个变量名,只需双击引用即可。
但是,当你在另一个度量(任何其他度量书写)计算里想再次引用该变量时,是不会存在Date01与Date03的。当然,最通俗的理解是:变量 ≠ 度量。 例如, 下面的代码定义了在两个不同的CALCULATE语句中用作筛选器的变量 :
DEFINE
VAR Selected_Colors = FILTER (ALL ( 'Product'[Color] ),
'Product'[Color] IN { "Purple", "Azure" })
EVALUATE
CALCULATETABLE ( 'Product', Selected_Colors)
当变量的定义遵循计算语法时,其作用区域仅限于作为计算语句引用的表表达式。下面的示例仅第一个计算语句定义的 SelectedColors 变量有效,而在其接下来的计算语句中对该变量的引用将失败 (请参见第10行 ), 因为该变量不可再次被访问。
EVALUATE
VAR Selected_Colors =
FILTER ( ALL ( 'Product'[Color] ),
'Product'[Color] IN { "Purple", "Azure" })
RETURN
CALCULATETABLE ( 'Product', Selected_Colors)
EVALUATE
RETURN -- 再次引用
CALCULATETABLE (
VALUES ( 'Product'[Brand] ), Selected_Colors) – 不起作用
虽然,我们期望通过 EVALUATE,再次引用 Selected_Colors这个变量,但由于该变量已在第一个 RETURN 后的CALCULATETABLE计算列表里被引用,不能再次被引用(只计算一次)。
有人把变量的这种一次性的引用计算、更像“常量”的行为称为:变量的“惰性”。
基于此, 你可以在前面的公式中的每个计算语句里分别定义一个变量,如下面的示例所示,变量 SelectColors 被计算两次(定义了两次)。
EVALUATE
VAR SelectedColors =
FILTER ( ALL ( 'Product'[Color] ),
'Product'[Color] IN { "Purple", "Azure" })
RETURN
CALCULATETABLE ('Product', SelectedColors)
EVALUATE
VAR SelectedColors =
FILTER (ALL ( 'Product'[Color] ),
'Product'[Color] IN { "Purple", "Azure" }) – 相同的变量被再次定义
RETURN
CALCULATETABLE (
VALUES ( 'Product'[Brand] ), SelectedColors)
前面这个公式中,相同的变量被再次定义使用。之外,定义的变量(相同的变量名称)可以在计算或任何其他 DAX 表达式中被重新定义,其定义的表达式可以相同或不同。
在下面的示例中,第一个计算返回SelectedColors 变量定义的"Purple"紫色或"Azure"天蓝色的颜色产品,而第二个计算则使用相同名称的SelectedColors 变量的另一个定义,其中表达式只包括"Red"红色和"White"白色的颜色产品。
DEFINE
VAR Selected_Colors =
FILTER (ALL ( 'Product'[Color] ), 'Product'[Color] IN { "Purple", "Azure" })
EVALUATE
CALCULATETABLE ( 'Product', Selected_Colors)
EVALUATE
VAR Selected_Colors =
FILTER ( ALL ( 'Product'[Color] ), 'Product'[Color] IN { "Red", "White" })
RETURN
CALCULATETABLE ( 'Product', Selected_Colors)
我们用更清晰的图示来表示它:
在"Power BI" 中,你可以在 "定义" 部分中声明许多变量,因此它可以在不同的查询中重复使用不同的可视对象的相同名称的变量。这些变量通常应用于报表中的可视对象展示的筛选器。
未完待续