CALCULATE 是至今为止 DAX 语言中最重要、最有用和最复杂的函数 引言
在本章中,通过深入介绍 CALCULATE 函数,我们将继续探索 DAX 语言的力量。实际上,同样的内容对于 CALCULATETABLE 也是适用的,只不过它返回一张表而不是标量值。为了简单起见,我们只在示例中使用 CALCULATE,但请记住 CALCULATETABLE 具有相同的行为。
专门用一整章来介绍这一个函数看似奇怪却很有必要,原因在于该函数的强大功能和副作用。CALCULATE 是至今为止 DAX 语言中最重要、最有用和最复杂的函数。在现实中该函数很简单:CALCULATE 仅执行一些特定类型的任务,但由于其可应用的场景数量之多以及公式编写之复杂,使得为其单独成章非常必要。
本章的内容比较复杂。如果是首次阅读,强烈建议你先阅读一遍以获得对 CALCULATE 的整体感觉,然后继续本书的其余章节。后期,一旦你对某个公式感到困惑,这时再回过头来从头开始阅读本章。每次你都可能有新的收获。
这一章的另一个重要特点是,我们需要有点“迂腐式的书生气”。因此,如果你发现某个部分的介绍很无聊,而且似乎只是在陈述显而易见的内容,请再仔细阅读一遍,以确保你完全理解它。
认识 CALCULAE 的作用
在 DAX 原理这一章中,你已经了解到有两种不同的上下文:行上下文和筛选上下文。我们到可以通过使用迭代器以编程方式创建行上下文,你应该也了解允许忽略筛选上下文的 ALL 函数。重要的是要记住,ALL 只是忽略筛选上下文,不会改变它。因此,在以下公式中:
- [Sales Amount Margin] :=
- SUMX (
- ALL ( Sales ),
- Sales[SalesAmount]
- * AVERAGE ( Sales[MarginPct] )
- )
- //SalesAmount 和 MarginPct 是 Sales 表的两列,此处不需要纠结这两列的业务逻辑,它们的作用和普通列相同
复制代码
ALL 忽略现有筛选上下文并始终返回整个表,但它不会改变公式其他部分的计值方式,事实上,在最内层的表达式中,AVERAGE 将在外部筛选上下文中计算 MarginPct 列的平均值。 DAX 中有一个可以更改筛选上下文的函数, 它就是 CALCULATE。
让我们从一个常用场景开始介绍 CALCULATE。假设你想要生成如图所示的报表, 其中包含产品类别、子类别和销售金额总和:
报告显示了按类别和子类别划分的销售额,SalesPct 列显示了每行占总计的百分比
报告显示了每行占总计的百分比。你可以使用 Excel 数据透视表功能轻松地生成这样的报告,但是我们感兴趣的是将百分比作为度量值来计算,以便用户可以随时将其添加到数据透视表中。
下面是一个简单的解决方案:
- SalesPct :=
- DIVIDE (
- SUM ( Sales[SalesAmount] ),
- SUMX (
- ALL ( Sales ),
- Sales[SalesAmount]
- )
- )
复制代码
分子是 SalesAmount 的总和。分母忽略筛选上下文, 并且始终返回 SalesAmount 的总计, 而不考虑任何筛选器。只要不从切片器中选择任何内容, 此公式就可以正常工作。例如, 如果在切片器中选择黑色,则值是错误的。总计的百分比是 18.76% 而不是 100%, 因为用于百分比计算的分母是一个高于实际值的数字,如图所示:
从切片器中选择颜色后显示了错误的百分比的结果
这里的问题很容易理解。通过使用 ALL, 我们忽略了筛选上下文。因此,分母始终是所有销售的总计,而如果选择一种颜色,我们希望保留颜色上的筛选器,只清除类别和子类别上的筛选器。ALL 和迭代函数在这里不是正确的选择,我们需要一个更强大的函数,也就是 CALCULATE。 |