DAX學習之理解上下文

DAX圣經(jīng)第二版出世后,一直想要用心讀一遍查漏補缺。事實證明體系化的閱讀是非常有必要的。讀完第四章,對于計算上下文的理解既輕松又簡單。本文會闡述當前我對DAX計算上下文的理解,做此記錄,希望共有裨益。

DAX中存在計算上下文、行上下文、篩選上下文,初學者往往暈頭轉向不知眾博客所云。這些上下文是DAX后續(xù)計算的脈絡,如人體動靜脈,不懂上下文就無法理解函數(shù)的運行奧秘,只能死記硬背背了又忘。

所謂計算上下文,依我理解就是DAX的計算環(huán)境,我有一個數(shù)據(jù)模型,數(shù)字們在函數(shù)中是如何組隊形成最終結果的,這整個一環(huán)境就是計算上下文。而計算上下文主要就分為行上下文和篩選上下文兩種。也就是說,一個函數(shù)怎么計算,關注其和行上下文的關系,和篩選上下文的關系,計算環(huán)境就大致告成了。

一、談談行上下文

談到行上下文,有些同學就會想到,在報表前端拉一張數(shù)據(jù)表或是矩陣表,指著其中的行列就說,這是行上下文。對嗎,當然不對。

從數(shù)據(jù)角度來說,一切報表前端的內容都是表象,我們真正在使用的是我們的基礎表,是數(shù)據(jù)模型中的表,是構成表關系的表。

所以計算的本質,在于計算我們的基礎表。行上下文作為計算上下文,也就是計算環(huán)境中的一大組成部分,其針對的對象自然也是我們的基礎表。行上下文就是對基礎數(shù)據(jù)表的遍歷。給沒學過變成的同學解釋一下什么是遍歷:我有一百行數(shù)據(jù),我每行數(shù)據(jù)都讀了一遍,這就是遍歷。

什么時候會出現(xiàn)行上下文呢?有兩種情況。

①列計算的時候,行上下文就會自動出現(xiàn)。其實也很好理解嘛,你增加了一個新列,可不得每行都走一遍,才能說新建了一個列。一個新建列中,不能出現(xiàn)一個“黑洞”行吧:)

②度量值計算的時候,需要我們加入迭代器,行上下文就會出現(xiàn)。迭代器,可以理解為把基礎表每一行都遍歷一遍的工具。舉個例子,基本所有帶X的函數(shù),本質上都是個帶特殊技能的迭代器。比如SUMX:

Sales Amount = SUMX (Sales, Sales[Quantity] * Sales[Price] )

--注釋:Sales表中,?存在Quantity列和Price列。對每行數(shù)據(jù)都進行 [Quantity] * [Price]的計算,此時存在一個新的虛擬列,用于存放每行[Quantity] * [Price]的結果值。將這個虛擬列進行求和。

在上面的這個例子中,我引進了一個虛擬列的概念,便于各位理解。其實和①中相似了對嗎,只要需要對行數(shù)據(jù)產(chǎn)生新值或是計算(計算值也是新值),那么不管你是真實列還是虛擬列,都產(chǎn)生了行上下文。

值得注意的是,行上下文只和單表對象有關。如果A表和B表是一對多的單向關系,A表發(fā)生行上下文,也就是A表被遍歷和迭代了,這對B表有影響嗎?

答案是沒有。因為遍歷存在于一張表中。舉上面的例子,假設A表中有Quantity列和Price列,我對這兩列進行SUMX的遍歷求和,雖然B表和A表存在關聯(lián)關系,但針對列的遍歷是無法跳到B表上去執(zhí)行的。

那如果A表有Price列,B表有Quantity列,我們有需求對A表和B表進行同時遍歷怎么辦?一種同學會想,那我在一開始導入數(shù)據(jù)時,對A表和B表做left join的關聯(lián)查詢呀,把B表的Quantity列取到A表中,就又可以在一張表中執(zhí)行遍歷了。這是一種方案,但如果我們在建模時已經(jīng)做好了A表和B表的一對多單向關系,不妨直接用DAX函數(shù)進行關聯(lián)取列。

我們引入Related和Relatedtable這兩個函數(shù),解決該問題。這兩個函數(shù)通常也是為了實現(xiàn)多表間的行上下文存在的,即實現(xiàn)多表間的同時迭代。從函數(shù)名的字面理解看,我們大致也能猜到,Realtedtable返回的是一張表,那么相對應的,Realted返回就是一個單值。這是為了匹配我們關系中的一對多和多對一而存在的。

在上面的例子中,我們已經(jīng)假設A表和B表是一對多的單向關系,A是一端,B是多端。也就是說,一個A表值可能對應到多個B表值。那么從A表出發(fā),我們使用關系函數(shù)的時候,B表應該返回多值,是一張表的形式,所以在這個例子中,我們應該使用Relatedtable(B)。

二、談談篩選上下文

篩選上下文其實也很好理解,就是篩選嘛。你這計算環(huán)境中存在篩選嗎,這也是DAX計算時需要考慮的事情。

PBI表格

大家可能覺得,篩選嘛,還能不認識啊。別說,真有人不認識,以上PBI表格中,有哪幾個篩選?篩選上下文中的篩選,和我們狹義的篩選并不一致,除了切片器,頁面級篩選、報表級篩選,還存在行篩選、列篩選。如上圖所示,2016、2017、蘋果、三星、小米,這都是篩選器。我們的度量值只有一個sum,但我們的結果卻被這些行和列分割得七七八八。

值得注意的是,篩選上下文是早于DAX計算的。也就是說,在公式計算之前,篩選上下文就已經(jīng)發(fā)揮作用了。比如上圖中第一個計算格中的15574.7是怎么來的?在“年”=2016年和“品牌”=蘋果的數(shù)據(jù)中,我去計算銷售總和,得到15574.7。

上面我們講了行上下文只作用于單表對象,作用到其他表時,我們需要用到關系函數(shù)才可以實現(xiàn)。篩選上下文的作用對象是什么呢?答案是數(shù)據(jù)模型。也就是說,只要A表和B表存在關系,且關系可以正向流通,那么篩選就會自動傳遞。

三、一個實例(嵌套行上下文)

一個非常好玩的例子,如果我們不會用Rank函數(shù),我們該如何求出銷售經(jīng)理的銷量排名。思路是,找出比我銷量高的銷售經(jīng)理,他們的人數(shù)+1就是我的排名。以下是我們的DAX demo:

Rank =

VAR CurrentPersonAmount = Sales[Amount]

VAR PersonBeforeMe = CountRows(Filter(Sales[Amount],Sales[Amount]>CurrentPersonAmount))

Return PersonBeforeMe+1

這邊涉及兩個迭代,一個是新增Rank列時,PBI會自動產(chǎn)生一個行上下文,得到這個行上下文作用的是變量CurrentPersonAmount,也就是說,變量CurrentPersonAmount中的Amount值,會自動遍歷一遍Sales表。

而第二個迭代,其實是嵌套在第一個迭代中的,由Filter產(chǎn)生。Filter是個帶特殊功能的迭代器,他會對Sales表中的Amount列,逐個進行遍歷。

可能有些同學沒聽懂,我把內部發(fā)生的事情再闡述一遍:當CurrentPersonAmount處于Sales表的第一行時,執(zhí)行一次變量PersonBeforeMe的計算,此時變量PersonBeforeMe中CurrentPersonAmount的值,依舊是第一行的Amount,但PersonBeforeMe中的Sales[Amount],將會遍歷一遍Sales表,這是Filter這個迭代器發(fā)揮的作用。這邊會依次選出大于第一行Amount值的所有Amount值,以便返回第一行Amount前面有幾個比他大的Amount。

這樣,第一個Amount的排名就基本確定了,接下來,CurrentPersonAmount跳到Sales表的第二行,再次執(zhí)行變量PersonBeforeMe的計算,以此類推。

總結一下,被嵌套的行上下文,如果需要引用外部行上下文的內容,可以用變量的形式進行傳遞。

一個小檢測,此時的你,能理解earlier函數(shù)的含義了嗎?提示,earlier函數(shù)就是為了引用外部行上下文的內容而產(chǎn)生的函數(shù)。。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容