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

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

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

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

不難發(fā)現(xiàn),其結(jié)果是預(yù)期的,同時發(fā)現(xiàn):
根本沒有用到 { 1 , 3 } 以及其中的元素,在更復(fù)雜的場景中,業(yè)務(wù)上需要:在內(nèi)層可以訪問到外層同名的列。
多層迭代 - 內(nèi)外跨層穿越
考察上面已經(jīng)有的結(jié)構(gòu):
迭代 迭代
[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] )。
那么,函數(shù) EARLIER 就起到了跨層穿越的效果。
多層迭代 - 默認穿越
在理解上述內(nèi)容后,來看一道測試題吧:
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。
而實際的結(jié)果是:
在這個場景中,SUMX ( B , [B] * [A] ) 與 SUMX ( B , [B] * EARLIER( [A] ) ) 完全一致。
結(jié)果如下:

以及:

也就是說,在這個場景下的 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這讓我們得到以下結(jié)論:
DAX 提供了迭代中需要訪問當前元素的機制,叫做:行上下文。
迭代是可以嵌套的。
在嵌套的迭代中,內(nèi)層可以訪問外層。
若列不遮擋,也就是使用不同層的不同名列,則可以直接訪問,也可以使用 EARLIER 顯式指定要訪問的相對第 X 外層。
若列有遮擋,也就是使用不同層的相同名列,則默認使用內(nèi)層,這必須使用 EARLIER 顯式指定要訪問的相對第 X 外層。
不論是內(nèi)層或者外層,都處于(或有自己)相應(yīng)的行上下文。
總結(jié)
要理解 EARLIER 就要知道行上下文;
要理解 行上下文就要知道迭代;
迭代是遍歷大量元素的邏輯手段;
在數(shù)據(jù)模型中,大量元素以邏輯行的形式存在于表中;
遍歷表的元素,就是表的行;
從正在遍歷(迭代)的行中取出值需要一個機制來框住當前行,稱為:行上下文;
迭代是可以多層嵌套的;
從更內(nèi)層迭代中的行上下文可以訪問相對外層迭代中的行上下文,這時使用 EARLIER 即可。
EARLIER,顧名思義,更早的,意思為更早創(chuàng)建出的行上下文。
用 EARLIER 實現(xiàn)的這種牛叉特性可以起一個牛叉的名字:跨層穿越。
BI佐羅講解的 DAX 是從本質(zhì)層面進行的,本質(zhì)不表示大而全,而是邏輯的完備和簡潔,學(xué)習 EARLIER 竟不需要任何一個業(yè)務(wù)表,因為基本數(shù)學(xué)知識足以。學(xué)習《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é)習
掃碼與PBI精英一起學(xué)習,驗證碼:data2021
PowerBI MVP 帶你正確而高效地學(xué)習 PowerBI
點擊“閱讀原文”,即刻開始
↙
