彻底理解 PowerBI DAX 函数 EARLIER

共 4848字,需浏览 10分钟

 ·

2021-02-02 21:33

很多业务背景的伙伴进入 DAX 世界后,第一个拦路虎就是 EARLIER。

因为这是我们业务人员平时不用的思维逻辑:迭代。

迭代,是区分文科与理科;业务与 IT 的标志性思维逻辑。

迭代,在传统的编程领域又叫循环,迭代是循环的等价。

本文让您彻底理解 EARLIER 以及迭代,不管你是什么背景。

什么叫迭代

迭代,简单说就是数数;而精确说,就是:对已知集合中元素的遍历。

例如:我们有一个集合:{ 1, ... , 10 },对这个集合的遍历,就是挨个看一遍。

例如:我们有一个集合:{ 苹果,鸭梨,橘子,香蕉 },对这个集合的遍历,就是挨个看一遍。

从这个意义上来说,迭代本身是很傻的,光看不做事。

所以,伴随着着迭代,一般都得做点坏事,不然不白迭代了,白看了。

理解 DAX 中的 SUM

在 DAX 中,SUM 的用法如下:

[Sales] := SUM( Order[Amount] )

它完全等价于:

[Sales] := SUMX( Order , Order[Amount] )

其含义为:

对 Order 表进行迭代,并把遍历到的数据行的 [Amount] 列的值提取出来全部加起来。

从逻辑上来讲,SUMX 有两个重要动作:

  • 在遍历的元素的时候提取元素

  • 最后在遍历完成时全部加起来

注意:实际 DAX 引擎的物理执行可能与此不同,但逻辑上可以这么理解。

SUMX 中隐藏的迭代器

SUMX 的执行如下:

SUMX( Order , Order[Amount] ) = 

【 迭代开始{ 】

row1 , 取出当前行 [Amount]
row2 , 取出当前行 [Amount]
row3 , 取出当前行 [Amount]
row4 ,取出当前行 [Amount]
...
【 } 迭代完成 】

【【将所有取出的值相加并返回。】】

其中:

  • 【迭代开始{ ... } 迭代完成】为隐藏的内置迭代器

  • 【【..】】为迭代完后的内置操作

由于这两步逻辑被 SUMX 隐藏了,很多业务背景的伙伴就不得理解:

  • 到底迭代器长成啥样

  • 迭代里面发生了啥

  • 迭代完了发生了啥

以上图示为了更加形象地说明这个过程。

迭代中的行上下文

在 DAX 中,表可以是这样的:

{ 1 , 2 , 3 }

// 或者这么写
{
1,
2,
3
}

这会得到:

由于没有给这个表的列起名字,这一列默认叫 Value,那么来考察:

    SUMX (
{
1,
2,
3
},
[Value]
)

可以得到:

在迭代中,可以从[Value]列取出值必须要能锁定当前的行,就是行上下文。

也就是说,在迭代中,遍历的每个元素就是行上下文,在行中可以取出列值,否则无法做到。

注意

很多初学者问:什么叫行上下文?其实更应该换一个问法。

一个更好的问题应该是:

在迭代一个集合的时候,DAX 是否有什么机制来让用户可以操作正在遍历的元素?

回答:

DAX 有这种机制,并起名叫:行上下文,用来取出迭代中正在遍历的元素。

这很好,正如我们的预期。

进入烧脑阶段开始。

多层迭代 - 同名覆盖

请考察:

    SUMX (
{ 1, 3 },
SUMX ( { 1, 2 } , [Value] * [Value] )
)

对于 { 1 , 3 } 来说,它有一列叫:[Value];

对于 { 1 , 2 } 来说,它也有一列叫:[Value]。

注意

由于两个 SUMX 的出现,也就出现了两套嵌套的迭代器,这就形成了在 迭代 中的 迭代,也就是:多层迭代

那么,此处的 [Value] * [Value] 到底指的是:谁的[Value] * 谁的[Value] 呢?

其执行细节如下:

[Value]    [Value]
1
1 1 * 1
2 2 * 2
3
1 1 * 1
2 2 * 2

这里用 TAB 的缩进表示了不同的层次。

请仔细观察上述内容,理解其规律。可以知道:[Value] 指的是 { 1, 2 } ,这是合理和自然的。也就是说:

迭代     迭代
[Value] [Value]
1
1 当前行上下文[Value] 1 * 当前行上下文[Value] 1 = 1
2 当前行上下文[Value] 2 * 当前行上下文[Value] 2 = 4
3
1 当前行上下文[Value] 1 * 当前行上下文[Value] 1 = 1
2 当前行上下文[Value] 2 * 当前行上下文[Value] 2 = 4

是实际执行的逻辑结构。其结果如下:

不难发现,其结果是预期的,同时发现:

根本没有用到 { 1 , 3 } 以及其中的元素,在更复杂的场景中,业务上需要:在内层可以访问到外层同名的列。

多层迭代 - 内外跨层穿越

考察上面已经有的结构:

迭代     迭代
[Value] [Value]
1
1 当前行上下文[Value] 1 * 当前行上下文[Value] 1 = 1
2 当前行上下文[Value] 2 * 当前行上下文[Value] 2 = 4
3
1 当前行上下文[Value] 1 * 当前行上下文[Value] 1 = 1
2 当前行上下文[Value] 2 * 当前行上下文[Value] 2 = 4

如果我们希望这样呢:

迭代     迭代
[Value] [Value]
1
1 当前行上下文[Value] 1 * 上一层迭代的行上下文中的[Value] 1 = 1
2 当前行上下文[Value] 2 * 上一层迭代的行上下文中的[Value] 1 = 2
3
1 当前行上下文[Value] 1 * 上一层迭代的行上下文中的[Value] 3 = 3
2 当前行上下文[Value] 2 * 上一层迭代的行上下文中的[Value] 3 = 6

在 DAX 中就需要这样编写,如下:

可以看出:

EARLIER( C , X ) 的精确语义是:

上 X 层迭代的行上下文中的列 C 的值。

若 X = 1,可以忽略,将 EARLIER( [Value] , 1 ) 简写为 EARLIER( [Value] )。

那么,函数 EARLIER 就起到了跨层穿越的效果。

多层迭代 - 默认穿越

在理解上述内容后,来看一道测试题吧:

    VAR A = SELECTCOLUMNS( { 1, 3 } , "A" , [Value] )
VAR B = SELECTCOLUMNS( { 1, 2 } , "B" , [Value] )
RETURN SUMX (
A,
// 这里需要放一句话
)

这里需要放一句话,请选择:

  • 选项 1 - SUMX ( B , [B] * [A] ),且选项 2 语法错误

  • 选项 2 - SUMX ( B , [B] * EARLIER( [A] ) ),且选项 1 语法错误

在不做实验的情况下,请选择 A 还是 B 呢?

如果选项 1 对,那么说明:[A] 的访问,由于无同名列的遮挡,不需要跨层,也不能跨层,所以不能用 EARLIER;

如果选项 2 对,那么说明:[A] 的访问,虽然无同名列的遮挡,由于不同层,必须要跨层,所以必须用 EARLIER。

而实际的结果是:

在这个场景中,SUMX ( B , [B] * [A] ) 与 SUMX ( B , [B] * EARLIER( [A] ) ) 完全一致。

结果如下:

以及:

也就是说,在这个场景下的 SUMX ( B , [B] * [A] ) ,如下:

   迭代     迭代
[A] [B]
1
1 当前行上下文[B] 1 * 当前行上下文[A] 1 = 1
2 当前行上下文[B] 2 * 当前行上下文[A] 1 = 2
3
1 当前行上下文[B] 1 * 当前行上下文[A] 3 = 3
2 当前行上下文[B] 2 * 当前行上下文[A] 3 = 6

完全等价于这个场景下的 SUMX ( B , [B] * EARLIER( [A] ) ) ,如下:

   迭代     迭代
[A] [B]
1
1 当前行上下文[B] 1 * 上一层迭代的行上下文中的[A] 1 = 1
2 当前行上下文[B] 2 * 上一层迭代的行上下文中的[A] 1 = 2
3
1 当前行上下文[B] 1 * 上一层迭代的行上下文中的[A] 3 = 3
2 当前行上下文[B] 2 * 上一层迭代的行上下文中的[A] 3 = 6

这让我们得到以下结论:

  • DAX 提供了迭代中需要访问当前元素的机制,叫做:行上下文。

  • 迭代是可以嵌套的。

  • 在嵌套的迭代中,内层可以访问外层。

    • 若列不遮挡,也就是使用不同层的不同名列,则可以直接访问,也可以使用 EARLIER 显式指定要访问的相对第 X 外层。

    • 若列有遮挡,也就是使用不同层的相同名列,则默认使用内层,这必须使用 EARLIER 显式指定要访问的相对第 X 外层。

  • 不论是内层或者外层,都处于(或有自己)相应的行上下文。

总结

要理解 EARLIER 就要知道行上下文;

要理解 行上下文就要知道迭代;

迭代是遍历大量元素的逻辑手段;

在数据模型中,大量元素以逻辑行的形式存在于表中;

遍历表的元素,就是表的行;

从正在遍历(迭代)的行中取出值需要一个机制来框住当前行,称为:行上下文;

迭代是可以多层嵌套的;

从更内层迭代中的行上下文可以访问相对外层迭代中的行上下文,这时使用 EARLIER 即可。

EARLIER,顾名思义,更早的,意思为更早创建出的行上下文。

用 EARLIER 实现的这种牛叉特性可以起一个牛叉的名字:跨层穿越

BI佐罗讲解的 DAX 是从本质层面进行的,本质不表示大而全,而是逻辑的完备和简洁,学习 EARLIER 竟不需要任何一个业务表,因为基本数学知识足以。学习《BI真经》,窥见更多本质。

让数据真正成为你的力量

Create value through simple and easy with fun by PowerBI

Excel BI | DAX Pro | DAX 权威指南 | 线下VIP学习

扫码与PBI精英一起学习,验证码:data2021

PowerBI MVP 带你正确而高效地学习 PowerBI
点击“阅读原文”,即刻开始

浏览 131
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报