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

理解行上下文

任何 DAX 表达都是在上下文中计算的。上下文是公式计值的“环境”,也就是说,公式的结果始终受到环境的影响。总有两种上下文,它们分别是:筛选上下文和行上下文,统称为计值上下文。这篇文章让我们来认识行上下文

初识行上下文

这次,我们思考一个不同的公式:

Sales[GrossMargin] = Sales[SalesAmount] - Sales[TotalCost]

你可能会在计算列中编写这样的表达式,以便计算毛利。在计算列中定义此公式后, 你将得到下面这个结果。

为表的所有行计算毛利

DAX 为表的所有行计算公式, 对于每一行, 它都按预期计算出了不同的值。为了理解行上下文,我们在阅读公式时需要有点较真精神:我们要求减去两列,但我们在哪里告诉 DAX 从表的哪一行获取列的值?你可能会说要使用的行是隐式的。因为它是计算列,DAX 按行计算它,对于每行,它计算不同的结果。这是正确的,但是从 DAX 表达式的角度来看, 关于使用哪一行的信息仍然缺失。

实际上,用于执行计算的行并不存储在公式中。它由另一种上下文定义:行上下文。当定义计算列时,DAX 从表的第一行开始迭代;它创建了一个包含该行的行上下文并计算表达式。然后它移到第二行,再次计算表达式。此行为发生在表的所有行,如果表有一百万行,你可以认为 DAX 创造了一百万个行上下文来计算公式一百万次。显然,为了优化计算,真实情况并非如此;否则的话 DAX 将是一种非常慢的语言。无论如何,从逻辑的角度来看,这就是它的工作原理。

计算列逐行计算数量*价格

总有两种上下文

到目前为止,你已经了解了什么是行上下文和筛选上下文。它们是修改公式结果的最常见的途径。任何公式都将在这两个不同的上下文中进行计算:行上下文和筛选上下文。

我们称这两种上下文为“计值上下文”,因为它们改变了公式计值的方式,为同一个公式提供了不同的结果。

这是一个非常重要并且很难在初期就意识到的问题:总是有两种上下文,一个公式的结果同时取决于这两个上下文。身处 DAX 学习路径的当前阶段,你可能认为这是显而易见的,非常自然。你可能是对的。然而,在后面的文章中,如果你不记得这两种上下文的共存关系,你会发现公式变得难以理解,因为每一个上下文都会改变公式的结果

创建行上下文的方式

你已经了解了当定义计算列时可自动创建行上下文,这是由于在此种情况下 DAX 表达式基于逐行计值。现在是时候来学习如何通过迭代器在 DAX 表达式内部创建行上下文了。

我们知道在 DAX 中以 X 结尾的函数都是迭代函数,它们循环整张表并为每行计值一个表达式,最后使用不同算法来聚合结果。例如,在以下 DAX 表达式中:

[IncreasedSales] := SUMX ( Sales, Sales[SalesAmount] * 1.1 )

SUMX 是一个迭代函数。它迭代整个销售表且每行都对销售金额按 10%加成来计值,最后返回所有这些值的总和。为了对每行计值该表达式,SUMX 对销售表创建了行上下文并用于迭代过程中,使得内层表达式(SUMX 的第二个参数)在包含了当前迭代行的行上下文中计值。

重要的是要注意,在整个计值流中 SUMX 的不同参数使用了不同上下文。现在让我们更近一步观察该表达式:

= SUMX (
        Sales,                      ← 外部上下文
        Sales[SalesAmount] * 1.1    ← 外部上下文和新的行上下文
  )

第一个参数 Sales 在计值时使用了来自外部环境(例如可能是一个数据透视表单元格,其他度量值查询的一部分)的上下文,而第二个参数(表达式)计值时同时使用了外部上下文和新创建的行上下文。

所有迭代器均以相同方式工作,具体如下:

  1. 在作为第一参数接收到的表上创建一个新的行上下文。
  2. 对于表中的每一行,在新创建的行上下文内部对第二个参数计值(也包括在迭代开始前已经存在的其他上下文)。
  3. 如果迭代器需要,对步骤 2 中计算出的值进行聚合。(还有一些迭代函数如 FILTER 和 ADDCOLUMNS 不执行此聚合步骤)
重要的是要记住:原始上下文在表达式内部仍然有效。迭代函数仅添加了一个新的行上下文,而不以任何方式修改已有上下文。该规则几乎总是有效的,但有一个重要例外:对于同一张表,如果之前上下文中已包含了行上下文,那么此行上下文被新创建的行上下文覆盖。在下一篇文章中我们会详细讨论这个问题。

行上下文总结

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

下载面板

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

6
说点什么

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

FILTER和ADDCOLUMNS是迭代函数,怎么理解?我一直以为是筛选函数!

SueSu
游客
SueSu

FILTER是一个迭代器,它迭代表的所有行,并返回一个新表。理解了,谢谢!还是要往后再看看

pleasureyuer
成员
pleasureyuer

= SUMX (
Sales, ← 外部上下文
Sales[SalesAmount] * 1.1 ← 外部上下文和新的行上下文
)

针对这个计算,“表达式内部的原始上下文仍然有效”这句话指的是可能存在的筛选上下文么?

pleasureyuer
成员
pleasureyuer

要使用行上下文,要么通过计算列、要么通过迭代函数。
行上下文不筛选,只进行迭代,确定计算发生在哪一行。
聚合函数可以转换为等价的聚合X函数,在没有任何筛选的情况下迭代计算每一行的值并最后聚合