DAX 中的筛选上下文可视化解释
本文翻译自Marco Russo&Alberto Ferrari的文章—《Filter context in DAX explained visually》来源:SQLBI 这篇文章使用基于视觉表示的概念模型来描述DAX筛选上下文。
筛选上下文是编写良好DAX代码时需要理解的一个基本概念。在本文中,我们使用视觉方法来描述筛选上下文——我们依赖于图形可视化,该可视化表示了当您使用报表的视觉元素、筛选器和切片器时,筛选上下文中存在的不同交互。这是规划获得所需结果所需更改的第一步:这些更改可以通过使用CALCULATE函数来实现,该函数在筛选上下文中删除、添加和替换现有筛选器。
本文为已经在其他筛选上下文文章中讨论过的主题提供了不同的视角:阅读它们可以更深入地了解这一对DAX来说非常重要的概念。
每个单元格都有不同的筛选上下文
报表中的每个数字都是通过在特定筛选上下文中评估DAX表达式来生成的。相同的表达式会产生不同的结果,因为它总是在不同的筛选上下文中进行评估。因此,矩阵中的每个单元格和图表中的每个数据点都有不同的筛选上下文。
我们通过描述矩阵视觉对象中一个单元格上应用的筛选器来分析筛选上下文。下面的图片描述了返回8,776.54的高亮单元格的筛选上下文。
该单元格显示了2019年在美国和加拿大销售的蓝色Contoso产品的销售额。筛选上下文中的每个筛选器都是一个表,其中包含语义模型中一列或多列“可见”的值列表。在这个第一个例子中,有四个筛选器,每个筛选器都筛选一列,其中Brand、Color和Year列各筛选了一个值;Country列有两个可见的值,这对应于切片器中的选择(加拿大和美国)。
在筛选上下文中评估的所有表函数仅返回通过筛选器应用于筛选上下文而“可见”的那些行。筛选上下文以极其高效的方式筛选模型中的表。此外,筛选器仅在评估聚合或迭代器时才会被“消耗”。稍后,我们将看到,使用CALCULATE函数,我们可以在执行昂贵的聚合之前操作筛选上下文,从而在灵活性和性能方面带来好处。
一个筛选器是一张表
第一个重要概念是,筛选上下文中的筛选器是一个表,它包含一列或多列的值列表。在前面的例子中,切片器选择了两个国家,这些值列在相应的筛选器中。但是,即使筛选器对数字列使用“小于”之类的运算符进行指定,筛选器也总是用满足筛选条件的该列现有值的列表来表示。例如,如果报表中的筛选窗格有一个条件表示净价小于10.00,则相应的筛选器包括该列中满足该条件的唯一值的列表。筛选器中的值数量取决于该列中存在的唯一值数量。
我们知道,表示筛选上下文的一种更直观的方式是编写定义了筛选器的筛选条件。在前面的图片中,我们可能会倾向于写“< 10.00”而不是满足该净价条件的唯一值列表。这本来可以起作用,但仅限于某个程度。实际上,对于更复杂的筛选器,如果不使用这种表示法,就无法描述结果。如果您想探究这一点,请使用Power BI Desktop中的DAX查询视图查看示例文件中的“复杂筛选器”查询——但这不是本文的目标。
获取目标筛选上下文
当你编写一个计算时,你通常可以在同一个视觉对象或不同的视觉对象中显示计算中涉及的所有数字。报表中的每个数字都是在特定筛选上下文中执行的度量的结果。每当我们需要这个数字时,我们只需要在该筛选上下文中评估该度量。因此,在编写DAX公式之前,最好先描述计算中涉及的每个术语的筛选上下文。
例如,考虑一个“颜色百分比”度量,它返回每种颜色的销售额百分比。以下报表显示了Contoso品牌中每种颜色在仅筛选加拿大和美国两个国家的情况下的百分比。在编写任何DAX代码之前,我们可以用英语描述这个计算,即某种颜色(Contoso品牌中蓝色产品的销售额为11,791.62)的销售额与所有颜色(Contoso品牌中所有产品颜色的销售额为202,753.05)的销售额之间的除法。在以下图片中,我们突出了这个除法的分子和分母,并描述了每个术语的筛选上下文。
我们可以将‘颜色百分比’度量编写为两个度量之间的除法,即‘销售额’和‘所有颜色销售额’之间的除法:
销售表中的度量
% of Color =
DIVIDE (
[Sales Amount],
[Sales All Colors]
)
当前筛选上下文中的现有‘销售额’度量提供了除法的分子的值。‘所有颜色销售额’度量必须在目标筛选上下文中评估‘销售额’。
移除筛选器
通过比较两个筛选上下文,我们可以改变初始筛选上下文(分子)以获得目标筛选上下文(分母),进而计算所需的度量值。例如,“颜色百分比”度量值有一个初始筛选上下文,该上下文对应于除法的分子。此筛选上下文包含三个筛选器:蓝色、Contoso 品牌、加拿大和美国。目标筛选上下文仅包含两个筛选器,它们与初始筛选上下文(品牌和国家)没有区别。它们之间唯一的区别是颜色筛选器,该筛选器在目标筛选上下文中不存在。
我们可以通过从初始筛选上下文中移除颜色筛选器来获得“所有颜色销售额”的目标筛选上下文。使用 CALCULATE 函数时,会暂时复制初始筛选上下文(分子),然后 REMOVEFILTERS 函数会从 Product[Color] 中移除筛选器,最后在修改后的筛选上下文(分母)中评估销售额度量值。
这是“所有颜色销售额”的定义:
销售表中的度量
Sales All Colors =
CALCULATE (
[Sales Amount],
REMOVEFILTERS ( 'Product'[Color] )
)
也可以使用 ALL 代替 REMOVEFILTERS——它们在 CALCULATE 中的行为是相同的,但我们更倾向于使用 REMOVEFILTERS,因为它更好地描述了筛选上下文中执行的操作的语义:一个筛选器被移除,而不是被列中所有现有值的列表替换。
添加一个筛选器
我们已经看到了如何移除筛选器以获得目标筛选器上下文。在其他情况下,我们必须添加一个在初始筛选器上下文中不存在的筛选器。请记住,添加筛选器通常会减少将要聚合的行数,从而在求和时产生一个更小的数值。这在开始时可能有些违反直觉,因为我们“添加”了一个筛选器来“减少”结果!
销售表中的度量
Sales Contoso =
CALCULATE (
[Sales Amount],
'Product'[Brand] = "Contoso"
)
虽然筛选条件是一个表达式,但我们在目标筛选上下文中得到的是一个表格,其中包含按品牌筛选的值列表,对于这个例子来说,只有 Contoso。
只要应用于筛选上下文的筛选条件描述了筛选上下文未直接筛选的列的条件,那么筛选条件就简单地添加了一个筛选器。然而,如果已存在筛选器,那么我们就应该注意可能存在的现有筛选器的移除情况。
替换筛选器
另一种情况是在筛选上下文中用另一个筛选器替换现有的筛选器。例如,在以下报告中,我们希望以2017年为基准,比较各国多年来的销售额。基准2017度量将某年的销售额除以2017年的销售额。与之前示例中我们所见类似,我们可以将基准2017度量编写为两个度量之间的除法:
销售表中的度量
Benchmark 2017 =
DIVIDE (
[Sales Amount],
[Sales 2017]
)
当我们将初始筛选上下文(分子)与目标(分母)进行比较时,我们意识到应该将现有的年份筛选器替换为2017年。
当我们向筛选上下文添加筛选器时,CALCULATE 语法的结构与我们在前一个示例中看到的语法惊人地相似:
销售表中的度量
Sales 2017 =
CALCULATE (
[Sales Amount],
'Date'[Year] = 2017
)
确实,CALCULATE 中的筛选器参数将年份(2017年)的筛选器添加到了初始筛选上下文中。但是,年份上现有的筛选器(例如,2018年)被移除了,因为添加到筛选上下文中的每个筛选器都会自动移除与新筛选器涉及的列上存在的任何筛选器。
从DAX的角度来看,这就像是说每次向筛选上下文添加筛选器时,都会自动向同一个CALCULATE中添加对相同列的REMOVEFILTERS。因此,我们得到的结果与编写以下代码时相同:
销售表中的度量
CALCULATE (
[Sales Amount],
'Date'[Year] = 2017,
REMOVEFILTERS ( 'Date'[Year] )
)
将新筛选器与现有筛选器相结合
在前面的例子中,自动移除现有筛选器很有帮助,但当我们有不同要求时,我们可能希望改变这种行为。例如,假设我们必须创建一个“大额交易”度量值,该度量值返回那些金额大于1000的交易的销售金额。这个筛选器条件必须筛选两个销售列(数量和净价)相乘的结果,从而生成一个包含两列而不仅仅是一列的筛选器。但是,如果报表已经对数量或净价中的任何一个设置了筛选器,我们在计算时则不希望移除它。
解决方案要求将筛选器条件包装在KEEPFILTERS中:
销售表中的度量
Large Transactions =
CALCULATE (
[Sales Amount],
KEEPFILTERS (
Sales[Quantity] * Sales[Net Price] > 1000
)
)
我们可以逐步看到这种计算是如何工作的,以及筛选器上下文中所做的更改的说明。
Contoso 产品的销售金额的初始筛选上下文仅包含两个筛选器:品牌(Contoso)和净价。CALCULATE 中的 Sales[Quantity] * Sales[Net Price] > 1000 条件向筛选上下文添加了一个包含两列的筛选器(数量和净价)。KEEPFILTERS 的存在阻止了移除净价上现有的筛选器,否则该筛选器将被新筛选器移除。
结论
使用筛选上下文的图形表示对于规划使用 CALCULATE 的计算实现以及描述现有计算的行为都很有帮助。虽然引擎可能会使用优化来避免每个筛选器的实际具体化,但这种在筛选上下文中表示筛选器的方式可以解释筛选上下文操作的每个边缘情况。
您可以使用 CALCULATE 在筛选上下文中删除、添加和替换筛选器。本文的目的是为筛选上下文提供另一种视角,而不是替代我们在其他文章、书籍和视频课程中的现有材料。此外,没有比在自己的数据上实践更好的学习方式了。如果您是视觉学习者,我们希望这篇文章对您有所帮助,因为它为您提供了表示 DAX 中评估上下文背后抽象概念的另一个视角。
如果您想深入学习微软Power BI,欢迎登录网易云课堂试听学习我们的“从Excel到Power BI数据分析可视化”系列课程。或者关注我们的公众号(PowerPivot工坊)后猛戳”在线学习”。
长按下方二维码关注“Power Pivot工坊”获取更多微软Power BI、PowerPivot相关文章、资讯,欢迎小伙伴儿们转发分享~
Power Pivot工坊
自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)