2021年3月版本的 Power BI Desktop 引入了一个新语法,简化了 CALCULATE 函数中复杂筛选条件的编写。简而言之,以下度量现在是有效的 DAX 表达式:
Red or Contoso Sales :=CALCULATE ([Sales Amount],'Product'[Color] = "Red" || 'Product'[Brand] = "Contoso")
Big Sales Amount :=CALCULATE ([Sales Amount],KEEPFILTERS ( Sales[Quantity] * Sales[Net Price] > 1000 ))
DAX 之前的工作方式
在 DAX 中,筛选器是表,不是布尔条件。因此,在 CALCULATE 中编写布尔条件只是较长语法的语法糖形式。例如,以下度量值:
Red :=CALCULATE ([Sales Amount],'Product'[Color] = "Red")
对应于以下完整语法,其中对 Product[Color] 的筛选是一个 - 包含筛选上下文中允许的值 - 的列表:
Red Sales :=CALCULATE ([Sales Amount],FILTER (ALL ( 'Product'[Color] ),'Product'[Color] = "Red"))
此自动转换仅支持引用单列的布尔条件。可以多次引用同一列,例如以下度量值:
Red or Blue Sales :=CALCULATE ([Sales Amount],'Product'[Color] = "Red" || 'Product'[Color] = "Blue")
然而,不能在同一布尔条件中引用多列。在这种情况下,一个包含多列的筛选器参数需要完整的语法,如以下示例所示:
Red or Contoso Sales :=CALCULATE ([Sales Amount],FILTER (ALL ( 'Product'[Color], 'Product'[Brand] ),'Product'[Color] = "Red" || 'Product'[Brand] = "Contoso"))
一个常见的错误做法是:使用表筛选而不是多列筛选。例如,在本文开始的示例中,Big Sales Amount 度量值通常被以下面次优的方式编写:
Big Sales Amount :=CALCULATE ([Sales Amount],FILTER (Sales,Sales[Quantity] * Sales[Net Price] > 1000))
再次强调下,编写此筛选器参数的最佳实践是:编写多列筛选而不是表筛选。以下版本的 Big Sales Amount 使用 KEEPFILTERS 函数只是为了保留上一个未优化版本的语义:
DEFINEMEASURE Sales[Big Sales Amount] =CALCULATE ([Sales Amount],KEEPFILTERS (FILTER (ALL ( Sales[Quantity], Sales[Net Price] ),Sales[Quantity] * Sales[Net Price] > 1000)))EVALUATESUMMARIZECOLUMNS (Sales[Quantity],"Sales Amount", [Sales Amount],"Big Sales Amount", [Big Sales Amount])
| Quantity | Sales Amount | Big Sales Amount |
| 1 | 17,569,935.65 | 4,097,102.62 |
| 2 | 2,951,553.65 | 1,516,230.38 |
| 4 | 5,735,255.24 | 4,424,075.64 |
| 3 | 4,334,599.44 | 2,865,005.14 |
但是,最后两个版本的语法都和本文初始示例中的语法不同。接下来,我们将详细阐述。
DAX 现在的工作方式
DAX 自2021年3月引入的新语法现在已支持:在 CALCULATE 的同一个布尔条件形式的筛选器参数中引用同一表的多列 。
因此,以下 Big Sales Amount Overrides Filter 度量值现在是一个有效的 DAX 表达式:
Big Sales Amount Overrides Filter :=CALCULATE ([Sales Amount],Sales[Quantity] * Sales[Net Price] > 1000)
在 DAX 内部,引擎转换成以下代码执行计算:
Big Sales Amount Overrides Filter :=CALCULATE ([Sales Amount],FILTER (ALL ( Sales[Quantity], Sales[Net Price] ),Sales[Quantity] * Sales[Net Price] > 1000))
新的筛选覆盖在 Sales[Quantity] 和 Sales[Net Price] 上的任何已有的筛选。例如,Big Sales Amount Overrides Filter 度量值将忽略一个对 Sales[Quantity] 筛选的切片器。我们可以使用 KEEPFILTERS 函数保留切片器上已有的筛选,如文章开头所示的 Big Sales Amount 度量值:
DEFINEMEASURE Sales[Big Sales Amount] =CALCULATE ([Sales Amount],KEEPFILTERS ( Sales[Quantity] * Sales[Net Price] > 1000 ))MEASURE Sales[Big Sales Amount Overrides Filter] =CALCULATE ([Sales Amount],Sales[Quantity] * Sales[Net Price] > 1000)EVALUATESUMMARIZECOLUMNS (Sales[Quantity],"Sales Amount", [Sales Amount],"Big Sales Amount", [Big Sales Amount],"Big Sales Amount Overrides Filter", [Big Sales Amount Overrides Filter])
| Quantity | Sales Amount | Big Sales Amount | Big Sales Amount Overrides Filter |
| 1 | 17,569,935.65 | 4,097,102.62 | 12,902,413.78 |
| 2 | 2,951,553.65 | 1,516,230.38 | 12,902,413.78 |
| 4 | 5,735,255.24 | 4,424,075.64 | 12,902,413.78 |
| 3 | 4,334,599.44 | 2,865,005.14 | 12,902,413.78 |
在同一布尔条件中引用的列必须属于同一个表。因此,以下表达式在 DAX 中仍然无效,因为它在同一个布尔条件中引用了不同表的列:
Sales Multiple or Red :=CALCULATE ([Sales Amount],Sales[Quantity] > 1 || 'Product'[Color] = "Red")
在上一种情况下,我们需要编写 FILTER 的完整语法形式。为了避免迭代多余的列,我们可以使用 CROSSJOIN,SUMMARIZE 或其他技术来确保迭代的表中只包含所需的列:
DEFINEMEASURE Sales[Sales Multiple or Red] =CALCULATE ([Sales Amount],FILTER (CROSSJOIN ( ALL ( Sales[Quantity] ), ALL ( 'Product'[Color] ) ),Sales[Quantity] > 1 || 'Product'[Color] = "Red"))EVALUATESUMMARIZECOLUMNS ('Product'[Brand],"Sales Amount", [Sales Amount],"Sales Multiple or Red", [Sales Multiple or Red])
| Brand | Sales Amount | Sales Multiple or Red |
| Contoso | 7,352,399.03 | 3,479,904.17 |
| Wide World Importers | 1,901,956.66 | 837,419.75 |
| Northwind Traders | 1,040,552.13 | 409,048.42 |
| Adventure Works | 4,011,112.28 | 1,778,525.69 |
| Southridge Video | 1,384,413.85 | 613,492.27 |
| Litware | 3,255,704.03 | 1,447,913.33 |
| Fabrikam | 5,554,015.73 | 2,422,741.32 |
| Proseware | 2,546,144.16 | 1,139,585.31 |
| A. Datum | 2,096,184.64 | 906,209.66 |
| The Phone Company | 1,123,819.07 | 479,841.37 |
| Tailspin Toys | 325,042.42 | 142,069.31 |
最佳实践仍保持不变
新语法不会改变任何最佳实践,但至少有助于应用 “筛选列,而不筛选表” 的规则。
多列之间的 AND 操作,最佳实践仍然是:编写多个只包含单列的布尔条件形式筛选器参数。
例如,以下度量值:
Red Contoso Sales Bad Practice :=CALCULATE ([Sales Amount],'Product'[Color] = "Red" && 'Product'[Brand] = "Contoso")
最佳实践仍然是:
Red Contoso Sales :=CALCULATE ([Sales Amount],'Product'[Color] = "Red",'Product'[Brand] = "Contoso")
始终应该仅在必要时才在同一个布尔条件中引用多列。如果以 - 两个仅包含单列的筛选器参数 - 代替一个包含两个仅仅执行简单 AND 操作的列的筛选器参数,运算速度将会更快。
结论
允许在 CALCULATE 的同一个筛选器参数中创建对同一表多列筛选的新语法大大简化了 DAX 代码,并且通常性能更佳。事实上,它生成的代码符合性能更佳的最佳实践。
如果你之前已经使用表筛选而不是仅筛选所需的列来编写多列布尔条件,当你用新的简单语法替换表筛选时,请记住:使用 KEEPFILTERS 以保持相同的语义。
下载案例文件?
回复公众号消息:CALCUALTE 新语法,获取下载链接。
Specifying Multiple Filter Conditions in CALCULATE
SQLBI

近期热读





