徹底理解 PowerBI DAX 函數(shù) EARLIER

很多業(yè)務(wù)背景的伙伴進(jìn)入 DAX 世界后,第一個(gè)攔路虎就是 EARLIER。
因?yàn)檫@是我們業(yè)務(wù)人員平時(shí)不用的思維邏輯:迭代。
迭代,是區(qū)分文科與理科;業(yè)務(wù)與 IT 的標(biāo)志性思維邏輯。
迭代,在傳統(tǒng)的編程領(lǐng)域又叫循環(huán),迭代是循環(huán)的等價(jià)。
本文讓您徹底理解 EARLIER 以及迭代,不管你是什么背景。
什么叫迭代
迭代,簡(jiǎn)單說就是數(shù)數(shù);而精確說,就是:對(duì)已知集合中元素的遍歷。
例如:我們有一個(gè)集合:{ 1, ... , 10 },對(duì)這個(gè)集合的遍歷,就是挨個(gè)看一遍。
例如:我們有一個(gè)集合:{ 蘋果,鴨梨,橘子,香蕉 },對(duì)這個(gè)集合的遍歷,就是挨個(gè)看一遍。
從這個(gè)意義上來說,迭代本身是很傻的,光看不做事。
所以,伴隨著著迭代,一般都得做點(diǎn)壞事,不然不白迭代了,白看了。
理解 DAX 中的 SUM
在 DAX 中,SUM 的用法如下:
[Sales] := SUM( Order[Amount] )它完全等價(jià)于:
[Sales] := SUMX( Order , Order[Amount] )其含義為:
對(duì) Order 表進(jìn)行迭代,并把遍歷到的數(shù)據(jù)行的 [Amount] 列的值提取出來全部加起來。
從邏輯上來講,SUMX 有兩個(gè)重要?jiǎng)幼鳎?/p>
在遍歷的元素的時(shí)候提取元素
最后在遍歷完成時(shí)全部加起來
注意:實(shí)際 DAX 引擎的物理執(zhí)行可能與此不同,但邏輯上可以這么理解。
SUMX 中隱藏的迭代器
SUMX 的執(zhí)行如下:
SUMX( Order , Order[Amount] ) =
【 迭代開始{ 】
row1 , 取出當(dāng)前行 [Amount]
row2 , 取出當(dāng)前行 [Amount]
row3 , 取出當(dāng)前行 [Amount]
row4 ,取出當(dāng)前行 [Amount]
...
【 } 迭代完成 】
【【將所有取出的值相加并返回。】】
其中:
【迭代開始{ ... } 迭代完成】為隱藏的內(nèi)置迭代器
【【..】】為迭代完后的內(nèi)置操作
由于這兩步邏輯被 SUMX 隱藏了,很多業(yè)務(wù)背景的伙伴就不得理解:
到底迭代器長成啥樣
迭代里面發(fā)生了啥
迭代完了發(fā)生了啥
以上圖示為了更加形象地說明這個(gè)過程。
迭代中的行上下文
在 DAX 中,表可以是這樣的:
{ 1 , 2 , 3 }
// 或者這么寫
{
1,
2,
3
}這會(huì)得到:

由于沒有給這個(gè)表的列起名字,這一列默認(rèn)叫 Value,那么來考察:
SUMX (
{
1,
2,
3
},
[Value]
)可以得到:

在迭代中,可以從[Value]列取出值必須要能鎖定當(dāng)前的行,就是行上下文。
也就是說,在迭代中,遍歷的每個(gè)元素就是行上下文,在行中可以取出列值,否則無法做到。
注意
很多初學(xué)者問:什么叫行上下文?其實(shí)更應(yīng)該換一個(gè)問法。
一個(gè)更好的問題應(yīng)該是:
在迭代一個(gè)集合的時(shí)候,DAX 是否有什么機(jī)制來讓用戶可以操作正在遍歷的元素?
回答:
DAX 有這種機(jī)制,并起名叫:行上下文,用來取出迭代中正在遍歷的元素。
這很好,正如我們的預(yù)期。
進(jìn)入燒腦階段開始。
多層迭代 - 同名覆蓋
請(qǐng)考察:
SUMX (
{ 1, 3 },
SUMX ( { 1, 2 } , [Value] * [Value] )
)對(duì)于 { 1 , 3 } 來說,它有一列叫:[Value];
對(duì)于 { 1 , 2 } 來說,它也有一列叫:[Value]。
注意
由于兩個(gè) SUMX 的出現(xiàn),也就出現(xiàn)了兩套嵌套的迭代器,這就形成了在 迭代 中的 迭代,也就是:多層迭代。
那么,此處的 [Value] * [Value] 到底指的是:誰的[Value] * 誰的[Value] 呢?
其執(zhí)行細(xì)節(jié)如下:
[Value] [Value]
1
1 1 * 1
2 2 * 2
3
1 1 * 1
2 2 * 2這里用 TAB 的縮進(jìn)表示了不同的層次。
請(qǐng)仔細(xì)觀察上述內(nèi)容,理解其規(guī)律。可以知道:[Value] 指的是 { 1, 2 } ,這是合理和自然的。也就是說:
迭代 迭代
[Value] [Value]
1
1 當(dāng)前行上下文[Value] 1 * 當(dāng)前行上下文[Value] 1 = 1
2 當(dāng)前行上下文[Value] 2 * 當(dāng)前行上下文[Value] 2 = 4
3
1 當(dāng)前行上下文[Value] 1 * 當(dāng)前行上下文[Value] 1 = 1
2 當(dāng)前行上下文[Value] 2 * 當(dāng)前行上下文[Value] 2 = 4是實(shí)際執(zhí)行的邏輯結(jié)構(gòu)。其結(jié)果如下:

不難發(fā)現(xiàn),其結(jié)果是預(yù)期的,同時(shí)發(fā)現(xiàn):
根本沒有用到 { 1 , 3 } 以及其中的元素,在更復(fù)雜的場(chǎng)景中,業(yè)務(wù)上需要:在內(nèi)層可以訪問到外層同名的列。
多層迭代 - 內(nèi)外跨層穿越
考察上面已經(jīng)有的結(jié)構(gòu):
迭代 迭代
[Value] [Value]
1
1 當(dāng)前行上下文[Value] 1 * 當(dāng)前行上下文[Value] 1 = 1
2 當(dāng)前行上下文[Value] 2 * 當(dāng)前行上下文[Value] 2 = 4
3
1 當(dāng)前行上下文[Value] 1 * 當(dāng)前行上下文[Value] 1 = 1
2 當(dāng)前行上下文[Value] 2 * 當(dāng)前行上下文[Value] 2 = 4如果我們希望這樣呢:
迭代 迭代
[Value] [Value]
1
1 當(dāng)前行上下文[Value] 1 * 上一層迭代的行上下文中的[Value] 1 = 1
2 當(dāng)前行上下文[Value] 2 * 上一層迭代的行上下文中的[Value] 1 = 2
3
1 當(dāng)前行上下文[Value] 1 * 上一層迭代的行上下文中的[Value] 3 = 3
2 當(dāng)前行上下文[Value] 2 * 上一層迭代的行上下文中的[Value] 3 = 6在 DAX 中就需要這樣編寫,如下:

可以看出:
EARLIER( C , X ) 的精確語義是:
上 X 層迭代的行上下文中的列 C 的值。
若 X = 1,可以忽略,將 EARLIER( [Value] , 1 ) 簡(jiǎn)寫為 EARLIER( [Value] )。
那么,函數(shù) EARLIER 就起到了跨層穿越的效果。
多層迭代 - 默認(rèn)穿越
在理解上述內(nèi)容后,來看一道測(cè)試題吧:
VAR A = SELECTCOLUMNS( { 1, 3 } , "A" , [Value] )
VAR B = SELECTCOLUMNS( { 1, 2 } , "B" , [Value] )
RETURN SUMX (
A,
// 這里需要放一句話
)這里需要放一句話,請(qǐng)選擇:
選項(xiàng) 1 - SUMX ( B , [B] * [A] ),且選項(xiàng) 2 語法錯(cuò)誤
選項(xiàng) 2 - SUMX ( B , [B] * EARLIER( [A] ) ),且選項(xiàng) 1 語法錯(cuò)誤
在不做實(shí)驗(yàn)的情況下,請(qǐng)選擇 A 還是 B 呢?
如果選項(xiàng) 1 對(duì),那么說明:[A] 的訪問,由于無同名列的遮擋,不需要跨層,也不能跨層,所以不能用 EARLIER;
如果選項(xiàng) 2 對(duì),那么說明:[A] 的訪問,雖然無同名列的遮擋,由于不同層,必須要跨層,所以必須用 EARLIER。
而實(shí)際的結(jié)果是:
在這個(gè)場(chǎng)景中,SUMX ( B , [B] * [A] ) 與 SUMX ( B , [B] * EARLIER( [A] ) ) 完全一致。
結(jié)果如下:

以及:

也就是說,在這個(gè)場(chǎng)景下的 SUMX ( B , [B] * [A] ) ,如下:
迭代 迭代
[A] [B]
1
1 當(dāng)前行上下文[B] 1 * 當(dāng)前行上下文[A] 1 = 1
2 當(dāng)前行上下文[B] 2 * 當(dāng)前行上下文[A] 1 = 2
3
1 當(dāng)前行上下文[B] 1 * 當(dāng)前行上下文[A] 3 = 3
2 當(dāng)前行上下文[B] 2 * 當(dāng)前行上下文[A] 3 = 6完全等價(jià)于這個(gè)場(chǎng)景下的 SUMX ( B , [B] * EARLIER( [A] ) ) ,如下:
迭代 迭代
[A] [B]
1
1 當(dāng)前行上下文[B] 1 * 上一層迭代的行上下文中的[A] 1 = 1
2 當(dāng)前行上下文[B] 2 * 上一層迭代的行上下文中的[A] 1 = 2
3
1 當(dāng)前行上下文[B] 1 * 上一層迭代的行上下文中的[A] 3 = 3
2 當(dāng)前行上下文[B] 2 * 上一層迭代的行上下文中的[A] 3 = 6這讓我們得到以下結(jié)論:
DAX 提供了迭代中需要訪問當(dāng)前元素的機(jī)制,叫做:行上下文。
迭代是可以嵌套的。
在嵌套的迭代中,內(nèi)層可以訪問外層。
若列不遮擋,也就是使用不同層的不同名列,則可以直接訪問,也可以使用 EARLIER 顯式指定要訪問的相對(duì)第 X 外層。
若列有遮擋,也就是使用不同層的相同名列,則默認(rèn)使用內(nèi)層,這必須使用 EARLIER 顯式指定要訪問的相對(duì)第 X 外層。
不論是內(nèi)層或者外層,都處于(或有自己)相應(yīng)的行上下文。
總結(jié)
要理解 EARLIER 就要知道行上下文;
要理解 行上下文就要知道迭代;
迭代是遍歷大量元素的邏輯手段;
在數(shù)據(jù)模型中,大量元素以邏輯行的形式存在于表中;
遍歷表的元素,就是表的行;
從正在遍歷(迭代)的行中取出值需要一個(gè)機(jī)制來框住當(dāng)前行,稱為:行上下文;
迭代是可以多層嵌套的;
從更內(nèi)層迭代中的行上下文可以訪問相對(duì)外層迭代中的行上下文,這時(shí)使用 EARLIER 即可。
EARLIER,顧名思義,更早的,意思為更早創(chuàng)建出的行上下文。
用 EARLIER 實(shí)現(xiàn)的這種牛叉特性可以起一個(gè)牛叉的名字:跨層穿越。
BI佐羅講解的 DAX 是從本質(zhì)層面進(jìn)行的,本質(zhì)不表示大而全,而是邏輯的完備和簡(jiǎn)潔,學(xué)習(xí) EARLIER 竟不需要任何一個(gè)業(yè)務(wù)表,因?yàn)榛緮?shù)學(xué)知識(shí)足以。學(xué)習(xí)《BI真經(jīng)》,窺見更多本質(zhì)。

讓數(shù)據(jù)真正成為你的力量
Create value?through?simple and?easy?with fun?by PowerBI
Excel BI?|?DAX Pro?|?DAX?權(quán)威指南?|?線下VIP學(xué)習(xí)
掃碼與PBI精英一起學(xué)習(xí),驗(yàn)證碼:data2021
PowerBI MVP 帶你正確而高效地學(xué)習(xí) PowerBI
點(diǎn)擊“閱讀原文”,即刻開始
↙
