任何 DAX 表达都是在上下文中计算的。上下文是公式计值的“环境”,也就是说,公式的结果始终受到环境的影响。总有两种上下文,它们分别是:筛选上下文和行上下文,统称为计值上下文。这篇文章让我们来认识行上下文
初识行上下文
这次,我们思考一个不同的公式:
Sales[GrossMargin] = Sales[SalesAmount] - Sales[TotalCost]
你可能会在计算列中编写这样的表达式,以便计算毛利。在计算列中定义此公式后, 你将得到下面这个结果。
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 在计值时使用了来自外部环境(例如可能是一个数据透视表单元格,其他度量值或查询的一部分)的上下文,而第二个参数(表达式)计值时同时使用了外部上下文和新创建的行上下文。
所有迭代器均以相同方式工作,具体如下:
- 在作为第一参数接收到的表上创建一个新的行上下文。
- 对于表中的每一行,在新创建的行上下文内部对第二个参数计值(也包括在迭代开始前已经存在的其他上下文)。
- 如果迭代器需要,对步骤 2 中计算出的值进行聚合。(还有一些迭代函数如 FILTER 和 ADDCOLUMNS 不执行此聚合步骤)
= SUMX (
Sales, ← 外部上下文
Sales[SalesAmount] * 1.1 ← 外部上下文和新的行上下文
)
高老师请教一下上面的这个公式是不是可以通俗的这样理解;外部上下文会影响sumx第一参数,生成一个新的表,这个表决定了第二参数的迭代次数,第二参数(外部上下文和新的行上下文)可以理解为如果第二参数是聚合函数他的每行结果是受外部上下文影响,他的迭代次数是受新的行上下文影响,如果第二参数是表的列,则只受新的行上下文影响
高老师,图片中的红框1的意思是不是可以理解为,行上下文只迭代不筛选啊?红框2中的那句话,不理解,不明白是为了解释什么?
老师水平应该好, 但是措辞达意上有点摸不着头脑。在做参考阅读,疑惑很多
请问老师:
我在sales表和product表都用以下公式创建了计算列,同时还用以下公式创建了度量值,但是发现最终在可视化界面矩阵表里面的结果三个总计值都不一样,但是计算列每一列的计算结果跟度量值的总计值是一样的,无法理解,不应该是3个值都是一样的吗?
IncreaseSales2 = SUMX(Sales,Sales[SalesAmount]*1.1)
度量值=sumx(‘sales’,’sales'[net Price]*1.1)——假设无筛选上下文
请问老师,
sales 的行上下文是sales整表还是sales表的每一行
sales[net Price]的行上下文是sumx迭代的sales表的中每一行吗?
老师您好,请问:
= SUMX (
Sales, ← 外部上下文
Sales[SalesAmount] * 1.1 ← 外部上下文和新的行上下文
)
1. “外部”是不是针对计算列的行上下文而言的“外部”?
2. “第一个参数 Sales 在计值时使用了来自外部环境(例如可能是一个数据透视表单元格)”:我理解的“数据透视表单元格”是度量值所处的筛选上下文的环境,这句话是不是就是说明第一参数会被外部筛选器筛选?
3. “外部上下文和新的行上下文”:我是否应该理解为“对于外部上下文Sales中的每一行,所新创建的行上下文”?
谢谢老师!
读起来真的很拗口 难以理解
?因为它是计算列,DAX 按行计算它,对于每行,它计算不同的结果。这是正确的,但是从 DAX 表达式的角度来看, 关于使用哪一行的信息仍然缺失? 这中文表述是认真的么?
老师,SUMX这种迭代函数,第二个参数外部上下文和新的行上下文是并存的,但是不太懂,并存的时候计算关系是怎么样的。
= SUMX (all(Sales), Sales[SalesAmount])
= SUMX (all(Sales), SUM(Sales[SalesAmount]))
这里两个度量值,我发现第一个式子的外部筛选器对第二个参数不会有影响,只与行上下文有关,即使外部筛选器过滤掉那行了,依然会定位到那行进行计算。
第二个式子因为有SUM的存在,忽略了行上下文,就能感知到外部筛选器。
是不是说明有行上下文存在,并且没有被忽略的时候,筛选上下文是不起作用的?
读起来很拗口,难以理解。
理论的拗口句子好多,多加点例子吧。光看这些奇怪句子,是很难理解的
老师,计算列的筛选上下文 和 计算列的行上下文 有什么关系和区别?
这篇应该是主要参考了刘凯翻译的那本基于powerpivot创建数据模型的书
迭代函数不是保留外面的外部上下文(包括行上下文)么,那sum作为sumx的简化版,不是也应该保留行上下文么?
“聚合函数忽略行上下文,只考虑筛选上下文。”
老师,没读懂这句话,能具体解释下吗?
但有一个重要例外:对于同一张表,如果之前上下文中已包含了行上下文,那么此行上下文被新创建的行上下文覆盖。
老师,不明白这段文字,能举个例子解释下吗,谢谢
老师,我是初学者,看到这里有点晕。行上下文和筛选上下文有什么区别呢。筛选上下文可以理解为行、列、筛选器之类的集合成一张表。行上下文是指指定列对应的行?那如果我在筛选器上选择了唯一的一行和一列,那么形成的筛选上下文岂不是等于行上下文了。
行上下文是否可以理解为,是一个表格(行和列的阵列)?
FILTER和ADDCOLUMNS是迭代函数,怎么理解?我一直以为是筛选函数!
= SUMX (
Sales, ← 外部上下文
Sales[SalesAmount] * 1.1 ← 外部上下文和新的行上下文
)
针对这个计算,“表达式内部的原始上下文仍然有效”这句话指的是可能存在的筛选上下文么?