07.4 CALCULATE使用指南


本文是CALCULATE系列的最后一篇,是时候提供关于这个函数全面总结了。之后你在浏览其他文章的时候,很可能会多次回来参考本文的内容,不必担心,这是正常的。每当需要回忆CALCULATE的复杂行为时,你都可以在这里找到答案。不要因为反复查看本文内容而怀疑自己的学习能力,即使一些使用DAX多年的开发者,仍然必须提醒自己注意公式的计算规则。DAX是纯净且强大的语言,但一些容易被遗忘的细节往往能解决特定场景下的关键问题。# CALCULATE 总结

初始环境

CALCULATE在计值上下文中执行,该上下文包含一个筛选上下文,可能包含一个或多个行上下文,这是公式计值的初始环境。## 创建新的筛选上下文 CALCULATE创建一个新的筛选上下文,在其中计值第一个参数。新的筛选上下文只包含一个筛选上下文,由于上下文转换,新筛选上下文中所有的行上下文都消失了。## 接受三种参数 CALCULATE表达式接受三种参数:第一参数:必选,将在新筛选上下文中计值的表达式。显式筛选器参数:可选,操作原始筛选上下文,可能会使用调节器(Modifier),比如KEEPFILTERS。CALCULATE调节器:通过删除一些筛选器或更改关系结构,可以修改模型、调整初始筛选上下文的范围。## 执行上下文转换 当原始上下文包含一个或多个行上下文时,CALCULATE执行上下文转换,向上下文堆栈中添加不可见的隐式筛选器。默认情况下这些隐式筛选器会覆盖外部上下文提供的筛选器,而如果提供行上下文的是使用KEEPFILTERS的表表达式,这种情况下隐式筛选器的行为也会被KEEPFILTERS修改。# CALCULATE 计值流 当使用所有这些参数时,CALCULATE遵循一个非常精确的算法。当你需要理解某些复杂计算的时候,必须很好地理解这种算法。1. CALCULATE在初始计值上下文环境中的计算所有显式筛选器参数。初始上下文是公式外部环境,包括原始行上下文(如果有的话)和原始筛选上下文。所有显式筛选器参数独立于初始环境进行计算,计算完成后,CALCULATE开始构建新的筛选上下文。2. CALCULATE复制原始筛选上下文,以准备新的筛选上下文。这个过程中会丢弃原始行上下文,因为新的计值上下文将不包含任何行上下文。3. CALCULATE执行上下文转换。它使用列在原始行上下文中的当前值,为正在迭代的所有列提供一个具有唯一值的筛选器。此筛选器可能包含也可能不包含单个行,上下文转换并不保证新的筛选上下文只包含一行。如果没有活动的行上下文,则跳过此步骤。一旦上下文转换创建的所有隐式筛选器都应用于新的筛选上下文,计算就进入下一步。4. 计值调节器函数 USERELATIONSHIP、CROSSFILTER和ALL(ALL类型的函数)。这个步骤发生在步骤3之后。这非常重要,因为这意味着可以通过使用ALL来消除上下文转换的影响。CALCULATE调节器在上下文转换之后应用,因此可以更改上下文转换的效果。5. CALCULATE在原始筛选上下文中计值所有显式筛选器参数。将它们的结果应用于步骤4之后生成的新筛选上下文。一旦发生了上下文转换,这些筛选器参数就会应用到新的筛选上下文中覆盖转换生成的上下文。这个过程发生在步骤4之后,也就是ALL调节器移除上下文和模型关系结构更新之后,所以这一步生成的上下文不会被ALL*影响。同时,筛选器参数的计算发生在原始筛选上下文中,不受同一CALCULATE中任何其他调节器或筛选器的影响。最终,CALCULATE在步骤5生成的筛选上下文中计值第一参数。