DAX专题8: All/RemoveFilters/AllExcept/AllSelected-读书笔记(16)

一、ALL 函数
1️⃣ ALL函数 The ALL Function
语法:ALL( [<table> | <column>[, <column>[, <column>[,…]]]] )
参数为表或表的列,可以把表的多个列做为参数
▶️作为表函数使用时,返回表中去掉重复行表,或者列(多列)的所有唯一值的表(可能是单列表)
▶️作为修改筛选函数使用时,清除函数参数表或表[列]的所有筛选(即忽略表中所有的筛选器)。也可以把它叫计算修改器,因为它把计算中正在用的筛选条件全给拿掉了。
ALL函数是一个创建虚拟表的函数,返回一个没有重复行的表。
2️⃣ ALL函数和VALUES 函数比较 ALL Compared to VALUES
第十三章我们讲过可以通过新建表把函数创建的虚拟表变成一个实体表。在公式栏输入:
Product Colors All = ALL(Products[Color])

Product Colors Values = VALUES(Products[Color])

可以看到,这两个函数返回的结果没什么区别。但我们要注意,这两个函数还是有很重要的区别的:VALUES返回的表是遵循模型之前的筛选上下文,ALL函数会忽略(清除)所有的筛选上下文。用这两个函数创建的实体表不存在筛选上下文时返回的结果一样,但存在筛选上下文时则结果会很不同。
我们再写一个公式
Product Color/Category ALL = ALL(Products[Color],Products[Category])

用两个列做参数,返回一个不重复的两列表。我们上面的几个用法是为了测试,通常ALL是作为生成虚拟表的函数嵌套用在其它DAX公式里面的。ALL函数返回的虚拟表的行为就像模型中的实体表(从源导入的表)一样在模型中与其它表产生关系。因为ALL返回的表是虚拟表,我们并看不到它,这也是DAX中的表函数比较难学的原因之一。
3️⃣ 在度量值中使用ALL函数 Using ALL Inside Measures
ALL函数的通常是用在度量值中,ALL函数很有用,它可以清除来自可视化对象的筛选(VALUES返回的表是遵循模型之前的筛选上下文,ALL函数会忽略(清除)所有的筛选上下文。)
下面我们看下ALL的用法,创建一个矩阵,把 Products[Category]列放到矩阵行上,把之前写的度量值 [Total Number of Products] 放在值上

我们可以看到,矩阵中第一行Accessories 并没有筛选源表,第一行显示的是 Product Category = "Accessories"的产品数量,其实在背后的工作原理跟我们用筛选按钮选出Product Category = "Accessories"的逻辑是一样的,只不过矩阵的筛选是悄悄地在背后进行的。

矩阵和手工筛选出来的结果是一样的。
NOTE: 使用手工筛选按钮来检查DAX公式结果是一个很好的办法,写出一个度量值时,我们可以通过手工筛选、计算来检查度量值的结果是否正确。手工筛选数据表并不会影响报表的结果,它只是检查、测试、调试和学习的一种方法而已。
矩阵应用了行筛选(矩阵的行筛选产品表)以后,度量值再计算筛选剩下的表的行数做为度量值的结果。矩阵中每个值单元格的结果(包括总计)都是这样计算出来的。因为矩阵的总计单元格没有行筛选条件,所以总计就是产品表的全部行数。你也可以手工逐个检查计算每个单元格的筛选结果,肯定和度量值在矩阵中显示的结果一样。
下面我们用ALL和VALUES写三个度量值:
total productnumber = COUNTROWS(Products)
Total All Products = COUNTROWS(ALL(Products))
Total Values Products = COUNTROWS(VALUES(Products))
NOTE:公式里ALL使用表做为参数,没有使用表的列做为参数,这样写在ALL、VALUES函数中都可以。
ALL函数返回一个表,但这不能直接放在度量值里,可以在外面再套一个聚合函数,像COUNTROWS等让函数返回一个值。我们把度量值放在矩阵里看看结果

Products表的[Category]列被矩阵行字段筛选,度量值第二参数ALL(Products)把来自矩阵的筛选给全部扔掉了,嵌套ALL函数的度量值清除了所有筛选,返回一个固定值PRODUCT表的所有行数量,其它两个度量值则都被矩阵筛选了。通过这个例子我们不能明白ALL函数是怎么工作的了。
4️⃣ 在CALCULATE函数中使用ALL函数返回的表筛选条件 Using ALL as a Table Filter Inside CALCULATE
ALL函数通常用在CALCULATE函数中做为第二参数使用,就是做为CALCULATE的表筛选参数,它清除所有来自可视化对象的筛选条件。ALL函数的这个功能通常可以用在其它函数中嵌套使用。
计算每个国家销售占总销售的占比:
❇️ 我们先把国家放在矩阵的行上,把销售度量值放在值上
在值字段右键度量值,--将值 显示为--占总计的百分比。这样做可以得到占百分比,但我们不能继续使用这个值,比如我们想计算销售占比大于10%的国家数量,那就不行了,我们不能在其它计算方法中使用矩阵中的这处百分比值。如果想使用百分比结果,我们得写个度量值

5️⃣ 如果想使用百分比结果,我们得写个度量值
用ALL函数写个度量值 Writing Your Own DAX Measures by Using ALL
第一步:总计度量值
Total Global Sales =
CALCULATE([Total Sales], All(Territories))
第二参数返回Territories表的所有行,并清除矩阵的所有筛选
第二步:百分比度量值
% of Global Sales =
DIVIDE([Total Sales], [Total Global Sales])

两个练习
❇️Create a Grand Total Measure
Total Global Sales =
CALCULATE([Total Sales], All(Territories))
❇️Create the Percentage of Total
% of Global Sales =
DIVIDE([Total Sales], [Total Global Sales])

6️⃣ 快速度量值 Using the New Quick Measure Option
在矩阵值字段的某一度量值上右键,会弹出一个快速度量值子菜单,你可以不需要掌握什么DAX知识就能使用快速度量值。使用快速度量值比使用隐式度量值更好,您可以重命名快速度量值、编辑度量值、格式化度量值以及在其他度量中重用快速度量值。
❇️假如你要创建一个快速度量值,用于计算一个类别的总数。在新建快速度量值向导中,你需要做的就是将一个列或度量值从右边的字段列表拖到左边的相关区域中。本例中,将[Total Sales]度量值添加到Base Value值,将[Country]列添加到Category。
NOTE:快速度量值可以做为我们学习DAX的一个辅助工具,实际使用中还是建议大家使用DAX自己编写公式。
7️⃣ 在ALL中使用表或列 Passing a Table or a Column to ALL()
需要注意的是:在上面的例子中,我们使用另一种写法也能得到相同的结果,这次我们这样写
Total All Country Sales =
CALCULATE(
[Total Sales],
ALL(Territories[Country])
)
度量值第二参数ALL的参数是一个列。但是这个度量值在矩阵的行字段不是Territories[Country]时,结果就又变了。你可以对比一下下图中矩阵的第四列

二、REMOVEFILTERS 函数
Several times so far in this book, I have discussed the concept of syntax sugar . As a recap, this is a term that describes variations to functions that Microsoft developers sometimes create to make DAX easier to learn and understand. The REMOVEFILTERS() function is an example of syntax sugar . When I first learnt DAX, I learnt that the ALL() function is the “remove filters” function. In fact, I still teach this concept to my students today. So as you may have guessed, the REMOVEFILTERS() function is actually just syntax sugar for the ALL() function that you can use when you want to remove filters in the way shown above. Personally I never use REMOVEFILTERS() because I just learnt to do it using ALL(), but of course you can use it if you like.
在本书中,我已经多次讨论了语法糖(syntax sugar)的概念。回顾之前的解释,这个术语其实是微软开发人员有时为使DAX更容易学习和理解而创建的函数的变体(或者说是函数的一种简便写法)。REMOVEFILTERS()函数也可以理解为是语法糖的一个例子。Matt说他第一次学习DAX时,知道了ALL()函数是“清除筛选”的函数,他在教学时也是这样跟大家说的。其实我们可以把REMOVEFILTERS()函数当成是ALL()函数的语法糖,当你清除筛选时就可以使用REMOVEFILTERS()函数。使用REMOVEFILTERS()与否,看个人喜好。
语法:
REMOVEFILTERS([<table> | <column>[, <column>[, <column>[,…]]]])
• REMOVEFILTERS 只能用于清除筛选器,不能返回表。
• 在已计算的列或行级安全性 (RLS) 规则中使用时,不支持在 DirectQuery 模式下使用此函数。
三、ALLEXCEPT函数 The ALLEXCEPT() Function
ALLEXCELPT函数和ALL函数可以说是师出同门,功能有相似,但也有不同。ALL函数是可以清除整个表的筛选,也可以清除一列或多列的筛选,当你想清除一个表中很多列的筛选时,把这些列写到ALL函数太麻烦了。这时我们就可以使用ALLEXCEPT函数,把不需要清除筛选的列放到函数里就好了。我觉得可以用"非此既彼"来形容这个函数。
语法:
ALLEXCEPT(<table>,<column>[,<column>[,…]])
ALLEXCEPT 函数的第一个参数必须是对基表的引用。 所有后续参数必须是对基列的引用。 不能将表表达式或列表达式用于 ALLEXCEPT 函数。
返回值
删除了所有筛选器(针对指定列的筛选器除外)的一个表。
备注
此函数不单独使用,而是用作中间函数,可用于更改执行过其他计算的结果集。
可以在不同的方案中使用 ALL 和 ALLEXCEPT:

四、ALLSELECTED函数 The ALLSELECTED() Function
ALLSELECTED()函数的工作方式挺像ALL函数的,但是它们在其他视觉对象(例如切片器)和外部筛选区的工作方式不同。ALL会清除所有的筛选,不管你这个筛选在画布的哪里放着。ALLSELECTED听从外部筛选的(切片器、外部筛选区等),这一点在计算百分比时很有用。当报表中有其它筛选(例如切片器、外部筛选区或从另一个可视化交叉筛选),并且您希望矩阵中的总百分比加起来是100%时,就可以使用ALLSELECTED函数。
接着使用本章前面的例子的矩阵,现在添加了一个[Group]切片器,[% of Global Sales]合计为38.7%;这是正确的,因为其他占剩余61.3%的国家已经使用[Group]切片器过滤掉了。
语法:
ALLSELECTED([<tableName> | <columnName>[, <columnName>[, <columnName>[,…]]]] )
返回值:不带任何列和行筛选器的查询的上下文。
备注:
• 如果有一个参数,则该参数为 tableName 或 columnName。 如果有多个参数,则它们必须是同一表中的列。
• 此函数与 ALL() 不同,因为它保留了在查询中显式设置的所有筛选器,并且保留了除行和列筛选器之外的所有上下文筛选器。
• 在已计算的列或行级安全性 (RLS) 规则中使用时,不支持在 DirectQuery 模式下使用此函数。
TOTAL SALES = SUM('Sales'[ExtendedAmount])
TOTAL TERRITOY ALLSELECTED = CALCULATE([TOTAL SALES],ALLSELECTED(Territory))
% total allselected = DIVIDE([TOTAL SALES],[TOTAL TERRITOY ALLSELECTED])

五、临时度量值的用处 The Value of Interim Measures
把一个问题分成几步来做,在实际工作中很有用。建议大家写DAX时使用临时度量值(我觉得也可以叫中间度量值),然后再创建需要的度量值,最终使用的度量值可以引用临时度量值,这样做更方便,中间步骤正确,也便于得到正确的结果,或者容易排队错误,理解计算的中间步骤。这种方法和数学上的分步计算很相似。