https://zhuanlan.zhihu.com/p/64422393
經常有朋友提出一個問題,然后我給出一個DAX之后,TA又不是很理解,反復多次溝通才能把一個表達式講清楚。或者TA自己寫了一個度量值,可是對輸出結果無法理解:我想要的是A,為什么出來的是B?
為了幫助大家快速理解一個相對復雜的DAX,我把平時使用的方法拿出來分享如下。
為了介紹的簡潔清晰,以及大部分人的可理解性,本文的DAX並不算復雜,重要的是理解的步驟和思路。(我理解的復雜DAX就是看起來比較長的、經過多層函數嵌套的、計算邏輯較難理解的表達式)
DAX都應該有一個具體的應用場景,否則分析就沒有意義。
假設已有一個訂單表,需要匹配每個訂單的產品對應的采購成本金額;而成本表中的每種產品的采購成本是隨着時間變動的,成本生效以后,該產品銷售訂單的成本隨之變化,兩個表格結構如下圖,
問題看似簡單,其實需要匹配幾個條件,要匹配產品名稱、訂單日期對應的成本生效區間。轉換為數據分析語言,其實就是計算該產品的小於等於訂單日期的最近一個成本生效日期對應的采購成本。
在訂單表上"新建列",用DAX編寫如下,
單位成本 =
CALCULATE(MIN('成本表'[成本金額]),
TOPN(1, FILTER(ALL('成本表'), '成本表'[生效日期]<=
EARLIER('訂單表'[訂單日期])&&
'成本表'[產品名稱]=EARLIER('訂單表'[產品名稱])),
'成本表'[生效日期] ) )
然后每筆訂單對應的單位成本就被計算出來了,
當然這篇文章並不是為了匹配成本,而是理解這個DAX表達式。
對DAX熟悉的人,看到上面這個表達式並不難,但是如果是接觸DAX不是很久的同學,可能並沒有那么容易理解。
下面進入正題,通過以下幾個步驟來快速理解上述的DAX。
一 、格式化DAX
格式化就是對DAX進行合理的換行和縮進,表面上看起來更加簡潔美觀,更易於閱讀,其實最重要的是通過格式化可以更清晰的找出該表達式的設計邏輯和計算邏輯。
上述的表達式進行格式化處理以后,變成了這樣的,是不是很清晰很多呢。
當然當你看到的DAX已經是格式化的寫法,就沒有必要進行這一步了。
如果是你自己編寫的DAX,強烈建議從一開始就養成按格式書寫的好習慣,為以后進行數據分析編寫更復雜的DAX打下基礎。
上面這個表達式相對簡單,如果比這復雜幾倍,嵌套更多層的表達式,如果不進行格式化,想看懂其結構都非常困難,更別說理解其邏輯了。
二 、對DAX從內層向外逐層分解,不理解時通過輸出,來查看其計算結果。
通過上面格式化后的表達式,可以看出最內層的算是EARLIER函數,然后是FILTER函數的篩選表,之外又套了一個TOPN函數,最后由CALCULATE函數返回最終結果。
理解DAX函數的用法和邏輯,除了看關於該函數的介紹文檔,最直接的就是查看該函數的計算結果,下面就以一個實例來看看該DAX每一步的輸出內容。
以2月8日手機訂單對應的成本為例,來理解這個表達式是如何計算出單位成本為1300的。
第1層 | EARLIER函數
EARLIER函數之前介紹過(EARLIER 函數 | PowerBI星球),比較簡單,返回當前行對應的參數列,實質就是返回本行和參數列交叉的單元格。
那么EARLIER的計算結果如下,
EARLIER('訂單表'[訂單日期])返回:2018-2-8
EARLIER('訂單表'[產品名稱]返回:手機
第2層 | FILTER函數
有了第1層的結果,FILTER函數的表達式變成了,
FILTER(ALL('成本表'), '成本表'[生效日期]<= DATE(2018,2,8)&&'成本表'[產品名稱]="手機")
該表達式將篩選成本表中產品名稱為手機,並且生效日期早於或等於2018年2月8日的數據,通過新建表,該表達式的輸出結果如下:
回的正是按上述條件的篩選表。
第3層 | TOPN函數
FILTER函數的計算結果返回了早於訂單日期的所有行,為了找出最近的一次生效日期,使用TOPN函數返回按生效日期排序的第1行,利用上一步的計算結果,TOPN的表達式變為,
TOPN(1,'表1','表1'[生效日期])
同樣使用"新表"查看輸出結果,
把小於訂單日期的最近生效日期的所在行給篩選出來了。
第4層 | CALCULATE函數
經過TOPN的篩選,已經把成本表篩選的只剩下一行,在這一行中找采購單價已經非常簡單了,表達式變為,
CALCULATE(MIN('表2'[采購單價]),'表2')
這里用了MIN函數,實際上用MAX函數也是一樣的,因為只有一個值,最小值和最大值是相同的。
因為CALCULATE只能返回值,為了在表中查看輸出結果,所以外面套一個{},強制把單個值變為表,結果如下:
得出了2月8日手機的采購成本價格1300元。
以上對幾個嵌套函數的拆解,為了演示輸出結果,所以生成了表1、表2、表3等三個中間表,實際上原表達式一氣呵成,並不需要中間表,一次性輸出最終數據。
三 、復盤總結各函數的用法
通過以上的拆解,應該能完全理解上述表達式的計算過程了,但我們不能僅理解了這個表達式,更是要通過整體的計算邏輯,能舉一反三,掌握其中每個函數的用法,所以每次拆解以后,應該整體上進行復盤,思考一下表達式中主要函數的用法以及返回的結果是很必要的。
比如上述表達式中,至少可以總結出這些,
- EARLIER返回當前表的當前行與參數列交叉的單元格數據;
- FILTER函數根據第二個參數的篩選條件來篩選第一個參數表,返回的是一個表;
- TOPN函數返回參數表中按第三個參數排序的前N行,返回的也是一個表;
- CALCULATE函數返回聚合后的一個值。
經過以上的三個步驟的層層分解和復盤,不僅知道了DAX的輸出結果,而且對每一個函數的計算邏輯和過程進行了全面理解。
上述DAX雖然簡單,但即使是更復雜的表達式,通過以上的方式也都可以很快理解並掌握。
總結
通過以下幾個步驟快速理解一個相對復雜的DAX,
1,格式化:從整體上查看其結構,為第2步打基礎;
2,從內向外層層分解:必要時輸出結果查看計算邏輯;
3,分解后再整體復盤:總結每一個函數和參數的用法。
本文示例文件可通過公眾號回復關鍵字"理解DAX"獲取,業務場景來自於知識星球中一個朋友的提問,來知識星球,和我一起學習PowerBI。