[知识体系] 理解行上下文

  [复制链接]
查看199008 | 回复161 | 2021-2-21 19:33:47 | 显示全部楼层 |阅读模式
任何 DAX 表达都是在上下文中计算的。上下文是公式计值的“环境”,也就是说,公式的结果始终受到环境的影响。总有两种上下文,它们分别是:筛选上下文和行上下文,统称为计值上下文。这篇文章让我们来认识行上下文
初识行上下文

这次,我们思考一个不同的公式:
  1. Sales[GrossMargin] = Sales[SalesAmount] - Sales[TotalCost]
复制代码

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


7149211936391.png

为表的所有行计算毛利


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


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


7149211936392.png

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

总有两种上下文

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


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


创建行上下文的方式

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


我们知道在 DAX 中以 X 结尾的函数都是迭代函数,它们循环整张表并为每行计值一个表达式,最后使用不同算法来聚合结果。例如,在以下 DAX 表达式中:
  1. [IncreasedSales] := SUMX ( Sales, Sales[SalesAmount] * 1.1 )
复制代码

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


重要的是要注意,在整个计值流中 SUMX 的不同参数使用了不同上下文。现在让我们更近一步观察该表达式:
  1. = SUMX (
  2.         Sales,                      ← 外部上下文
  3.         Sales[SalesAmount] * 1.1    ← 外部上下文和新的行上下文
  4.   )
复制代码

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


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


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




  • 创建行上下文的方式有两种,计算列和迭代函数
  • 执行计算的行没有储存在公式内部,而是由行上下文定义。
  • 行上下文只包含一行(基于行号,永远不会重复),并且在被创建时自动定义。
  • 聚合函数忽略行上下文,只考虑筛选上下文。
  • 行上下文只用来决定引用目标列的哪个值。(即确定计算发生在哪一行)
  • 表格的列并没有某个确定的值,列在表格每一行都有一个值,如果你想让列取得某个值,需要确定这个值所在的行,而确定行的唯一方式是使用行上下文。
  • 要使用行上下文,要么通过计算列、要么通过迭代函数。
回复

使用道具 举报

邮差 | 2021-4-24 19:06:54 | 显示全部楼层
在撸一遍。。。
回复

使用道具 举报

ysg168 | 2021-6-16 15:20:06 来自手机 | 显示全部楼层
好,很好,非常好!
回复

使用道具 举报

aaronliu | 2021-6-24 12:56:57 来自手机 | 显示全部楼层
谢谢网站确实不错,超值
回复

使用道具 举报

文文 | 2021-8-10 16:01:07 | 显示全部楼层
占坑编辑ing
回复

使用道具 举报

冷无情 | 2021-9-1 06:54:03 来自手机 | 显示全部楼层
楼下的接上
回复

使用道具 举报

马可波罗 | 2021-9-20 20:21:29 | 显示全部楼层
前排支持下了哦~
回复

使用道具 举报

lovestopper | 2021-10-5 10:59:01 | 显示全部楼层
垃圾内容,路过为证。
回复

使用道具 举报

kyszg | 2021-10-11 21:50:58 来自手机 | 显示全部楼层
好,很好,非常好!
回复

使用道具 举报

benny1982 | 2021-10-25 22:32:39 | 显示全部楼层
专业抢沙发的!哈哈
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则