从数据到信息
从信息到洞察

理解上下文转换

上下文转换是 DAX 计值过程中一个非常灵活的部分,灵活的同时意味着复杂,DAX 的大部分复杂性都蕴含于此。上下文转换需要在理解 CALCULATE 函数的基础上学习。

初识上下文转换

在理解 CALCULATE 的行为之后,你知道这个函数在计值过程中会执行一项非常重要的任务:将任何现有的行上下文转换为等效的筛选上下文。这就是我们说的上下文转换。

为了演示该行为,我们创建一个包含 CALCULATE 表达式的计算列。由于计算列总是具有行上下文,因此会触发上下文转换。例如,在产品表中定义一个包含以下 DAX 表达式的计算列:

Product[SumOfUnitPrice] = SUM ( Product[Unit Price] )

公式对所有产品的标价求和。表达式在行上下文中计算,没有筛选上下文,因此它返回表中所有产品的单价之和,而不是正在计值的当前行产品的单价。你可以在下图中看到这种行为。

SumOfUnitPrice 在计算列中计值,返回所有产品单价的总和

现在,你可以将表达式稍作修改创建一个新的计算列,加入 CALCULATE

Product[SumOfUnitPriceCalc] = CALCULATE ( SUM ( Product[UnitPrice] ) )

什么?只有一个参数的 CALCULATE? 筛选器去哪儿了?实际上,我们用的是 CALCULATE 的极简形式。我们之前说过,CALCULATE 惟一的必选参数是第一参数,因此在不使用任何筛选器的情况下调用 CALCULATE 是完全可以的。在这种情况下,CALCULATE 不会使用其他条件更改现有的筛选上下文,它仍然执行你现在正在学习的行为:接受现有的行上下文(如果有的话),并将它们转换为等效的筛选上下文。请注意,所有现有的行上下文都合并到新的筛选上下文中,稍后我们会详细阐述。

在本例中,CALCULATE 查找现有的行上下文,并在产品表上发现一个由计算列定义的正在执行的行上下文。CALCULATE 考虑这个行上下文,并用一个筛选上下文取而代之,该筛选上下文只包含行上下文正在迭代的当前行。我们将此行为称为上下文转换。一般来说,我们将以上过程简述为CALCULATE 执行上下文转换,将所有行上下文合并到一个新的等效筛选上下文中

在 CALCULATE 内部,表达式 SUM ( Product[Unit Price] )在只包含产品表当前行的筛选上下文中计值,由于 CALCULATE 执行了上下文转换。这一次的结果与产品单价(unit price)相同,如图所示。

通过使用 CALCULATE,行上下文被转换为筛选上下文,改变了结果

当你第一次观察到这种行为,会发现很难理解为何 CALCULATE 要执行上下文转换。一旦开始使用之后你就一定会喜欢上该特性,因为多亏了它你才能创建强大的公式。

此外,上下文转换还有另一个非常重要的作用。你可能还记得,筛选上下文和行上下文以不同方式在关系中运行:行上下文不会自动沿着关系方向传递,而筛选上下文从关系的“一”端传递到“多”端。因此,当发生上下文转换时,筛选上下文会自动传递到相关的表。

通过在产品表定义以下两个新的计算列公式,你可以观察到这种行为:

Product[SalesAmount] = SUM ( Sales[SalesAmount] )

Product[SalesAmountCalc] = CALCULATE ( SUM ( Sales[SalesAmount] ) )

由 CALCULATE 引发的上下文转换影响了对相关表的筛选

如你所见,SalesAmount 列包含所有销售额的总计,而 SalesAmountCalc 只包含当前产品的销售额。CALCULATE 通过转换产品表的行上下文将筛选器传递到销售表,最终显示了当前产品的销售。

请注意,当 CALCULATE 计算时,所有活动的行上下文都会发生上下文转换。实际上,在不同的表上可能有多个行上下文。例如,如果你在产品表创建计算列,使用 AVERAGEX 迭代客户表,那么有两个行上下文(产品和客户)将发生上下文转换,销售表将接收两个筛选器。考虑以下表达式:

Product[SalesWithSUMX] =
AVERAGEX (
    Customer,
    CALCULATE (
        SUM ( Sales[SalesAmount] )
    )
)

公式计算的是消费者购买该产品的平均花费(不是平均价格,而是总花费的平均值)。CALCULATE 中的 SUM 函数在筛选上下文中计值,它只显示当前客户(由 AVERAGEX 迭代)和当前产品(由计算列迭代)的销售额。记住这个规则有一个简单的方法:在 CALCULATE 中没有行上下文,只存在一个筛选上下文

理解度量值中的上下文转换

理解上下文的转换非常重要,这是因为 DAX 还有另一个隐藏知识。到目前为止,我们一直使用函数和列来编写 CALCULATE 内部的表达式。但是,你还可以编写调用度量值的表达式。如果从计算列内部调用度量值会发生什么?更一般地说法是,如果从行上下文中调用度量值会发生什么?

作为示例,你可以这样定义一个名为 SumOfSalesAmount 的度量值:

[SumOfSalesAmount] := SUM ( Sales[SalesAmount] )

然后,你可以使用以下更简单的代码定义 SalesWithSUMX 计算列:

Product[SalesWithSUMX] =
SUMX (
    Customer,
    CALCULATE (
        [SumOfSalesAmount]
    )
)

自动添加的 CALCULATE

使用 CALCULATE 表明公式发生了上下文转换,问题是,每当你从另一个表达式中调用已定义好的度量值时,DAX 都会自动将度量值封装在 CALCULATE 中。因此,前面的表达式具有与以下表达式相同的行为:

Product[SalesWithSUMX] =
SUMX (
    Customer,
    [SumOfSalesAmount]
)

这个公式没有显式调用 CALCULATE,不过上下文转换依然在发生,因为DAX 自动为度量值添加了 CALCULATE

这就是为什么编写代码时要从写法上区分列和度量值的原因,我们遵循的书写标准是对度量值使用不完全限定名,列使用完全限定名。也就是避免将表名放在度量值的前面,但始终在列前面加上表名。
实际上,在前面的公式中,在 SumOfSalesAmount 之前没有表名说明 SumOfSalesAmount 是一个度量值,因此,你知道发生了上下文转换。

在嵌套中使用完整公式

上下文的自动转换使编写通过迭代执行复杂计算的公式变得容易。话虽如此,你仍然需要一些时间才能熟悉和使用这种技术。例如,如果你只想计算购买金额超过总体平均水平的客户的销售额总和,可以按如下方式编写度量值:

[SalesMoreThanAverage] :=
VAR AverageSales =
    AVERAGEX (
        Customer,
        [SumOfSalesAmount]
    )
RETURN
    SUMX (
        Customer,
        IF (
            [SumOfSalesAmount] > AverageSales,
            [SumOfSalesAmount]
        )
    )

在前面的代码中,我们使用 SumOfSalesAmount 作为在不同行上下文中计值的度量值。在定义变量时,我们使用它来计算客户销售额的平均值,而在 SUMX 的迭代中,我们使用它来检查当前客户的销售额与之前存储在变量中的平均值之间的关系。

基于 VAR 的语法更易于阅读和维护(公式的计算也可能更快)。然而,本质在于理解不同语法背后不同的公式计值流,可以不用 VAR,也无论你使用的是哪种 DAX 版本。如果没有真正理解和掌握这种上下文自动转换的机制,你可能花了大量时间阅读公式,但依然无法理解它的计算结果。

在公式内部调用度量值时,上下文转换会自动发生,无法避免。这意味着在调用度量值时避免上下文转换的唯一方法是展开它的代码。例如,假设你用另一种方法编写了前面的代码。不使用变量,而是定义一个称为 AverageSales 的度量值表示客户的平均销售额,如下面的代码所示:

[AverageSales] :=
AVERAGEX (
    Customer,
    [SumOfSalesAmount]
)
[SalesMoreThanAverage] :=
SUMX (
    Customer,
    IF (
        [SumOfSalesAmount] > [AverageSales],
        [SumOfSalesAmount]
    )
)

在突出显示的行中,使用了[AverageSales]计算客户的平均销售额。问题是此时你正在迭代(SUMX)中调用度量值,这会使上下文转换发生。因此,[AverageSales]的结果将不是所有客户的平均销售额,而是你正在迭代的客户的平均销售额。因此,测试总是会失败,度量值返回一个空值,因为 IF 的真值分支永远不会执行。如果想避免上下文转换,你需要将调用的度量值写成完整形式:

[SalesMoreThanAverage] :=
SUMX (
    Customer,
    IF (
        [SumOfSalesAmount]
            > AVERAGEX (
                Customer,
                [SumOfSalesAmount]
            ),
        [SumOfSalesAmount]
    )
)

使用完整形式后, SalesMoreThanAverage 现在返回正确的结果。此外,值得注意的是,在这种情况下整个公式有两个嵌套的行上下文, 三个度量值调用。其中两个计算由 SUMX 迭代的当前客户的销售额, 另一个 (在 AVERAGEX 内部) 计算由 AVERAGEX 迭代的当前客户的销售额。

理解这种特性之后你才能编写复杂的 DAX 代码来解决特定场景的需求。

触发上下文转换的条件

如果用一句话概况,DAX 中只有 CALCULATE 和 CALCULATETABLE 可以触发上下文转换。但在实际应用中,这句话需要你很好的理解,因为它有很多衍生形式,也就是公式中没有可见的 CALCULATE 函数,但上下文转换依然发生。比如:

  • 引用度量值,隐式调用的 CALCULATE
  • 部分时间智能函数,FIRSTDATE/LASTDATE、FIRSTNONBLANK/LASTNONBLANK 等,它们在内部使用 CALCULATE 函数。

上下文转换之后究竟有多少可见行?

上下文转换是指将行上下文转换为等效的筛选上下文。这个说法需要进一步作些澄清。

此处为隐藏内容 VIP会员和付费用户可见

小结

  • 上下文转换性能开销比较大如果迭代具有 10 列和 100 万行的表并使用上下文转换,则 CALCULATE 需要应用 10 个筛选器,总共 100 万次。无论如何,这将是一个缓慢的操作。这并不是说应该避免依赖上下文转换。然而,它确实是 CALCULATE 的一个需要小心使用的特性。
  • 上下文转换不仅过滤一行存在于 CALCULATE 外部的原始行上下文始终标识唯一行,因为行上下文逐行迭代。当通过上下文转换将行上下文转换为筛选上下文时,新创建的筛选上下文将筛选具有相同值集的所有行。因此,您不应该假设上下文转换只创建了一个只有一行的筛选上下文,这一点非常重要,需要仔细体会。
  • 上下文转换使用公式中不存在的列尽管筛选器使用的这些列不可见,但它们仍然是表达式的一部分。这使得任何带有 CALCULATE 的公式都比最初看起来复杂得多。如果使用上下文转换,则表的所有列都是表达式的一部分,作为隐藏的筛选器参数,此行为可能会创建意外的依赖关系。
  • 上下文转换从行上下文中创建筛选上下文您可能还记得这段表述:“行上下文迭代表,而筛选上下文筛选整个模型”。一旦上下文转换将行上下文转换为筛选上下文,它将更改筛选器的性质,不再只迭代一行,而是筛选整个模型;关系成为表达式的一部分。换句话说,发生在一个表上的上下文转换可能会将其筛选效果传递到远离行上下文来源的其他表。
  • 只要是存在行上下文的环境,上下文转换就会发生例如,如果在计算列中使用 CALCULATE,会发生上下文转换。计算列中有一个自动生成的行上下文,这足以使转换发生。
  • 上下文转换所有的行上下文当对多个表执行嵌套迭代时,上下文转换会考虑所有行上下文。它会使所有这些列无效,并为当前由所有活动行上下文迭代的所有列添加筛选器参数。
  • 上下文转换使行上下文无效虽然我们已经多次重复这个概念,但它值得再次引起您的注意。CALCULATE计算的表达式中没有任何有效的外部行上下文。所有外部行上下文都被转换为等效的筛选上下文。

理解上下文转换后的计值顺序

结合目前所学,相信你已经了解下面这两个在产品表中创建的计算列之间的区别:

Product[SumOfUnitPrice] = CALCULATE ( SUM ( Product[Unit Price] ) )

Product[SumOfAllUnitPrice] = CALCULATE ( SUM ( Product[Unit Price] ), ALL ( Product ) )

它们都是计算列,并且都使用了 CALCULATE,因此,两者都发生了上下文转换。

SumOfUnitPrice 应该只包含当前行的单价。然而,SumOfAllUnitPrice 的值是多少?出于直觉,因为有 ALL (Product),所以你很可能会期望它包含所有单价的总和。结果确实如此。然而,如果你遵循我们迄今所描述的规则,会发现这其中似乎还有一些问题。

事实上,ALL (Product)返回整个产品表,有效地从筛选上下文删除了任何产品筛选器。然而,与此同时,上下文转换将筛选产品表并只显示一行。如果你把这两个条件取交集(AND),那么由于上下文转换产生的筛选器约束性更强,因此,它应该会胜出。那么,为什么结果是所有单价之和,而不是当前行的单价呢?

此处为隐藏内容 VIP会员和付费用户可见

小测试

上下文转换并不是孤立的知识,需要掌握 CALCULATE 函数的计值过程才能正确理解,这里我假定你已经有一定的基础,通过下面三个案例,你可以测试一下自己对上下文转换的理解程度。

案例一

xSUM 是 Table1 的计算列,请思考在下图中它应该返回什么结果?公式是如何计值的?

当前表为 Table1

案例二

xRANK 是 Table2 的计算列,请思考在下图中它应该返回什么结果?公式是如何计值的?

当前表为 Table2

案例文件下载(附结果)

下载链接

案例三

[Test] 度量值的第 9 行 MAX (‘销售明细'[出库日期] ) 是否被第 3 行 VALUES (‘销售明细'[出库日期] ) 影响,为什么?

Test :=
MAXX (
    VALUES ( '销售明细'[出库日期] ),
    CALCULATE (
        SUM ( '销售明细'[下单数量] ),
        FILTER (
            ALL ( '销售明细'[出库日期] ),
            '销售明细'[出库日期]
                = MAX ( '销售明细'[出库日期] )
        )
    )
)

案例解析

案例一结果

xSum 列每行都等于 20。以表的第一行为例,公式计值过程如下:

此处为隐藏内容 VIP会员和付费用户可见

案例二结果

xRANK 列从上至下是 2,2,2,1,1,1。以表的第一行为例,公式计值过程如下:

此处为隐藏内容 VIP会员和付费用户可见

案例三结果

不影响。

此处为隐藏内容 VIP会员和付费用户可见

 

付费或下载说明

以上隐藏内容查看价格为5G 币,请先
注:加入 VIP 会员可享受全站权益,性价比更高。单独购买的内容长期有效,不受时间限制。

98
说点什么

1000
 
鼓掌微笑开心憧憬爱你色并不觉得吃瓜doge二哈喵喵思考笑哭捂脸悲伤大哭抓狂汗偷笑打脸捂眼黑线问号晕拜拜闭嘴衰咒骂ok作揖
26 评论数
84 被回复的评论
18 订阅评论的人数
 
查看最近回复
查看最热评论
  订阅本文评论  
最新 最旧 得票最多
提醒
成员
xianxing110a

老师,您能帮忙看看,这个结果为什么除了序号1的其他的都没有值,而且为什么得到的金额不是序号1的合计,而是当前行的值。同样的公式应用在计算列和度量值得到的结果就不一样了,想知道图片里面的结果计值流是怎么计算的,有点晕了

计指2.jpg
成员
139****3194

老师,案例2,计值解析中有几点不明白, ALL(Table2[value]) 返回的是什么表结构,是Value 1 2 3 6 7 8吗? 还是 a 1 b2 c3 a6 b7 c8?

如果返回的是前者,那么和计算列所在的外部第一行上下文转换为筛选上下文(第一行举例),筛选条件 category =a value =1 ,两个筛选上下文共同作用,value=1被内层转换的筛选上下文覆盖,所以VALUE列=1,2,3,6,7,8 而计算列外层行上下文转换的筛选上下文还有筛选器category=a, 后两者取并集(形成a 1,a 2,a 3,a 6,a 7,a 8)的最终筛选上下文。这里理解的对吗? 为什么会是并集?最后计算表达式的值为1列值(1,空,空,6 , 空,空),

然后再次调用计算列所在的第一行遇到calculate转换筛选上下文,并计算合计值为1,看这个1排上面列值中的排名(降序),返回2,老师为什么再次调用呢? 谢谢

成员
139****3194

老师,案例一:是否filter先筛选table1表里A列=a2的,然后返回一张表,构成内部筛选上下文(符合条件只有一行,A=a2,B=b2,value=20)。之后,calculate将外部行上下文转化为筛选上下文,拿第一行举例,这是转换的筛选上下文是 A=a1 B=b1 value=10,再然后外部转换的筛选上下文等级低,被内部筛选上下文替换或覆盖,最后,calculate 计值为20,其它行逻辑以此类推。
请问老师我的思维对吗,谢谢!

成员
xianxing110a

老师里面的示例文件哪里有下载的吗?

成员
139****9015

老师,案例二中,我理解外部和内部上下文形成筛选上下文, a 1 /a 2/a 3/a 6/a 7/a 8,但是不明白calculate(sum(table2 [value]))会返回 1 ,空,空,6,空,空。本人小白,请老师讲具体一点。

成员
嘿乎乎

老师,图片上 productkey列 我理解就是product表的主键啊(一端的product表根据productkey列跟sales表建立一对多关系),calculate转换上下文的结果不是应该只过滤productkey列吗,然后用all删除这列的过滤器,那结果就应该是所有行的unit price的加总,计算列应该返回一样的值啊? 不知道哪里理解的不对,麻烦老师解惑

QQ图片20200503210933.png
成员
xfxywy123

花了两个礼拜理解这个行上下文转换,对案例2总段稍微理解了一些,斗胆赘述,还请老师斧正。

案例2公式:xrank=rankx(all(table[value]),calculate(sum(table[value])))

基于rankx自然表达的计值过程:

rankx(table,expressin,value,order,ties)
rankx针对第一参数table的每一行创建新的行上下文,并基于该迭代的行上下文逐行计算expression,构成由expression的结果形成的列;然后value在外部行上下文(也就是所谓的计算列产生的迭代行上下文中)对当前迭代的计值上下文(包含行上下文和筛选上下文)进行求值value,然后返回value在expression构成的列中的排名,遵照order和ties的约定。
(顺便在这加上对所有迭代函数的通行理解,以X结尾的迭代函数,至少会包含两个参数table和expression,迭代函数沿着table每行创建迭代的行上下文,基于迭代的行上下文计算expression的值形成一列结果,最后视迭代函数的不同对该列值进行聚合(求和、平均等)

那么,前述问题理解其计值流的过程也就可以被拆解为:

①理解rankx的计值过程,主要是应用于expression和value计值环境的不同;
②理解calculate是如何转换两层行上下文以及内部筛选器是如何优先于转换的行上下文执行。

成员
xfxywy123

基于计算列创建的DAX公式计值流详解:

计值流:
Ⅰ、基于计算列生成的原始行上下文,也称为rankx的外部行上下文,计算列因这个隐藏的行上下文进行逐行迭代求解;
Ⅱ、计算列迭代到table的第一行,计算列公式rankx为迭代函数,基于第一参数all(table[value])的每一行创建新的行上下文,calculate(sum(table[value]))在前面创建的行上下文基础上求解并逐行迭代,计算的结果沿着第一参数形成一列值(实际不存在,只是用于后续的聚合操作);
Ⅲ、rankx函数的参数省略,则以代替,expression在计算列构成的行上下文(外部行上下文)基础上求解;
Ⅳ、expression在外部行上下文求得的解(亦即缺省的,有且仅有一个值)放到之前沿着all(table[value])计算calculate(sum(table[value]))构成的新列中,并返回其在该列中的位置,从而结束了rankx在table第一行的计值过程;
Ⅴ、计算列迭代到table的第二行,重新执行前述步骤,返回该行的expression在calculate(sum(table[value]))沿着all(table[value])的每行计值形成的列中的位置;
Ⅵ、完成计算列每一行的迭代计算。

成员
xfxywy123

再来解释关于all(table[value])和calculate(sum(table[value]))对计值过程的影响,

(插进第Ⅱ、Ⅲ计值步骤)基于前述,Ⅰ、Ⅱ计值步骤已经为函数生成了两层行上下文。单看all(table[value])此函数作用为为[value]列剔除所有筛选上下文条件并返回table这个表:

如果此时expression没有使用calculate碰巧转换了公式中存在的所有行上下文的话,那么实际上这个剔除筛选也就没有意义,因为此时此刻(不考虑外部筛选)该表中不存在对于[value]的筛选,亦即xRANK = RANKX(all(Table2[value]),SUM(Table[value]))和xRANK = RANKX(Table,SUM(Table[value]))应该是等效的(返回的每一行的结果是SUM(table[value])在计算列的当前外部行上下文的值,其在SUM(table[value])因迭代函数rankx沿着table每行形成的新的行上下文的计值形成的虚拟列中的排名;

那问题现在就出现在了calculate上,因为calculate的存在,导致现有的两层行上下文进行了上下文转换,继而由原本的计算列形成的迭代行上下文和rankx构成的沿着table的新的迭代行上下文全都转变成了筛选行上下文(这也就使得rankx的第一参数运用的all()函数起作用了————rankx对第一参数创建的新的行上下文因处于两重行上下文结构的内层,所以在发生上下文转换后覆盖(替换)了计算列的行上下文,并因由all()的原因,筛除了[value]列的筛选上下文,使得calculate(sum(table[value]))在发生行上下文转换后的的环境中计算时,只以=a为筛选条件逐行在=a,=1;=b,=2;=c,=3;=a,=6;=b,=7;=c,=8求解,得到了一列值{1,null,null,6,null,null}。

成员
xfxywy123

(插进第Ⅲ、Ⅳ计值步骤)基于前述,calculate(sum(table[value]))在计算列构成的外部行上下文基础上求值,因为calculate发生了行上下文转换,基于当前行的筛选条件=a,=1进行求解,得到应参与排序的值为1。

(插进第Ⅳ、Ⅴ计值步骤)值返回到之前的虚拟列中,得到=1在序列{1,null,null,6,null,null}的默认降序排名为2。

成员
成员
powersum

请问老师:一个度量值公式,采用calculate函数,如果calculate函数中的第一参数是迭代函数公式,那么如果公式是calculate的最简模式,即没有第二参数,那么和直接采用迭代函数是否效果是一样的。譬如:
[Correct Sales] := SUMX ( Sales, Sales[Quantity] * Sales[Unit Price] )

[Correct Sales] := calculate(SUMX ( Sales, Sales[Quantity] * Sales[Unit Price] ))是等效的。
是否正确呢?

成员
powersum

请问:小结中的这句话:“上下文转换不仅过滤一行。存在于 CALCULATE 外部的原始行上下文始终标识唯一行,因为行上下文逐行迭代”,我认为不对。因为calculate外部的原始行上下文是否就是透视表提供的透视环境呢?这可以是指向唯一行,也可以是某一类,取决于筛选字段的选择啊。

成员
xfxywy123

老师,几个问题:
1、在《初识上下文转换》中的示例,Product[SalesWithSUMX] =AVERAGEX ( Customer, CALCULATE ( SUM ( Sales[SalesAmount] ) )),因为calculate的存在,导致存在的两层行上下文(Product表中因计算列产生的原始行上下文、因Product和Customer表间关系沿主键传递的一层行上下文)发生了上下文转换,筛选关系传递到了Sales表(并因由Product-Sales、Customer-Sales表间关系)对Sales参与计算的行进行了筛选,最终得出由计算列筛选条件下的—— (产品表的)【当前产品】对应的(客户表)的所有客户的(销售表的)销售金额的平均值,我的理解对吗?
另外,计算列中的Calculate和[度量值]一样,只要出现就会使得所有的现存行上下文发生转换,会不会受到calculate内外的影响?
上述的例子是否等价于这个表达法:
Product[SalesWithSUMX] =Calcultae(AVERAGEX ( Customer, SUMX (Sales, Sales[SalesAmount] ) ))以及
Product[SalesWithSUMX] =Calcultae(AVERAGE ( SUMX (Sales, Sales[SalesAmount] ))(这个好像不对,这个好像是用当前产品迭代销售表的销售金额,计算的是当前产品的平均销售额)

成员
xfxywy123

2、在《上下文转换后究竟包括多少可见行》的部分,我可以理解定义主键前后发生上下文转换的区别,简单来说是“筛选的上下文是”发生在全部的列还是唯一的列(主键)并且沿唯一的列进行筛选传递,但是我在示例中不能理解:
[Wrong Sales] := SUMX ( Sales, [Sales Amount] ) 是计算所有相同行的销售额,
[Correct Sales] := SUMX ( Sales, Sales[Quantity] * Sales[Unit Price] ) 是计算每一行的销售额,
①首先这两个度量值也没涉及到上下文转换,因为不在前面提到的发生转换的条件中(包括调用Calculate/Calculatetable、调用度量值、调用时间智能函数等);
②及时发生了上下文转换,两者都应用于Sales表筛选当前表中所有的条件(假定他们没有定义任何主键),没道理一个筛选相同行另一个只筛选当前行啊。

成员
行者孙

请教,图中公式计算结果没有异议,但正好您说的在计算列中总有行上下文存在,那对于每一行这个结果6来说是不是没有意义?

Snipaste_2020-02-18_20-42-14.png