PowerBI之DAX神功:第2卷第1回 VAR變量
DAX神功第1卷我們學到了很多知識,建議大家學習DAX神功以文字版為主,多練習,視頻版為輔。我這個人很懶惰,無意義的事情我從來不做。我既然擔務(wù)這么多時間寫文字版,恰恰證明它重要,原理課,看視頻真的不是最佳選擇。2020年末已有前輩用視頻講原理,但是失敗了。原因在于,人腦的速度遠底于語言的速度,本身原理就需要思考和理解,原理課不同于案例的講解。
原理課的最佳學習方法是:我寫文字,你閱讀,你在測試過程中去理解。
一、為什么要用變量
1.代碼美觀,可讀性更強
這個問題因人而異,就好比你喜歡一個女演員,你認為她長得很好看,但是,總會有很多人認為你眼光有問題。所以,美觀和可讀性是因人而異的。
2.提高性能,這才是重點
學會一門功夫以后,可以隨時且多次的使用。不需要每次使用前再重新學一次吧?
情景一:張無忌不使用變量
步驟1:五年練成九陽神功
步驟2:練乾坤大挪移時需要九陽神功做鑰匙:五年練成九陽神功,1天練成乾坤大挪移
步驟3:來到光明頂,已經(jīng)是明教兄弟5周年祭日了
這里只是舉例,在DAX函數(shù)計算上,沒有這么夸張
孫興華個人想法:數(shù)據(jù)量較大時,建議使用Pandas或SQL等,汽車改裝的確可以提高速度,但是改裝成本高,也不安全;你追求速度,為何不使用速度更快的交通工具呢?
情景二:張無忌使用變量
定義以下兩個變量:
變量1:九陽神功=5年
變量2:乾坤大挪移=1天 因為有九陽神功做鑰匙
使用:直接調(diào)用變量即可
光明頂力戰(zhàn)六大派=九陽神功 + 乾坤大挪移
注意1.變量名不能與表同名
我個人的建議:新建列(不同表格的列除外),度量值,表名,變量名? 盡量使用唯一名稱,避免混淆
你不用腦子記憶哪些可以,哪些沖突,這完全是無意義的事情
一個公司的領(lǐng)導(dǎo)沒有辦法在招聘時不招同姓名的員工
但是,一個學校的教務(wù)處人員,他完全有能力將同姓名的學生不分在一個班級。
你現(xiàn)在就有能力,不將上述內(nèi)容定義為重名
注意2:變量名不能使用中文
二、變量可以賦值什么類型?
《DAX神功》第1卷第7回: 證明了變量可以是一張表
一班男生 =?
????????var tb1 = FILTER('Sheet1','Sheet1'[性別]="男")
return
????????FILTER(tb1,'Sheet1'[班級]="一班")
《DAX神功》第1卷第17回: 證明了變量可以是一個值
占比1=?
? ? VAR x = sum(Sheet1[銷量])
? ? VAR y = CALCULATE(sum(Sheet1[銷量]),ALL(Sheet1))
return
? ? DIVIDE(x,y)
Ps:當然,這個時候使用度量值計算也可以,我們只是舉例而已
網(wǎng)友提問:變量也可以是一個列呀,你使用過你怎么不承認呢?
《DAX神功》第1卷第14回
新建列 =?
????????var x='Sheet1'[序號]
return
????????sumx(FILTER('Sheet1','Sheet1'[序號]=x+1),'Sheet1'[銷售日期])?
答:如果你問出這樣的問題,那么你沒認真聽課,時間不夠可以一周學一集,欲速則不達。變量等于某個列時,代表的是這個列的當前行,仍然是一個值。

三、當標題值做變量時
1.變量要按順序引用
以VBA為例,基本所有語言都遵循這一原則

我們只是將變量a與變量b的順序交換,結(jié)果就不同了,為什么?有小學數(shù)學基礎(chǔ)便可理解。
VBA對沒有定義的變量默認為0或空字符,但是DAX對沒有定義的變量不能引用
DAX中無論新建列還是度量值情況都是這樣的:
測試1 =?
? ? VAR a=1
? ? VAR? ?b=a+1
? ? VAR? c=a+b
Return
? ? c

2.變量在其自身的VAR/Retrun代碼之外不可用 【有爭議】

【新建列】毛利額1=Calculate(sumx('Sheet1','Sheet1'[銷量]*'Sheet1'[售價]-'Sheet1'[銷量]*'Sheet1'[進價]))

【新建列】
毛利額2 =?
? ? VAR x='Sheet1'[銷量]*'Sheet1'[售價]
? ? VAR y='Sheet1'[銷量]*'Sheet1'[進價]
return
? ? CALCULATE(sumx('Sheet1',x-y),all(Sheet1[毛利額1]))
解釋:《DAX神功》第1卷第14回講到,當新建列時,變量是某列代表當前行
Ps:因為我們在一個表中新建列時,使用了多次Calculate,會出現(xiàn)循環(huán)依賴,所以我們要取消【毛利額1】的篩選,詳見《DAX神功》第1卷第20回 循環(huán)依賴什么鬼?

接下來我們看看度量值應(yīng)該怎么寫?
【度量值】毛利額3 = Sumx('Sheet1','Sheet1'[銷量]*'Sheet1'[售價]-'Sheet1'[銷量]*'Sheet1'[進價])
解釋:Sumx創(chuàng)建行上下文,放到度量值中,就自動轉(zhuǎn)換成篩選上下文
但是變量這樣寫就不行了,具體原因在《DAX神功》第1卷第14回講過了
毛利額4 =?
? ? var x='Sheet1'[銷量]*'Sheet1'[售價]
? ? var y='Sheet1'[銷量]*'Sheet1'[進價]
return
? ? sumx('Sheet1',x-y)
解釋:我們講當前行時,討論過這樣的情況
那應(yīng)該怎么寫呢?
毛利額4 =?
? ? var x=SELECTEDVALUE('Sheet1'[銷量])*SELECTEDVALUE('Sheet1'[售價])
? ? var y=SELECTEDVALUE('Sheet1'[銷量])*SELECTEDVALUE('Sheet1'[進價])
return
? ? sumx('Sheet1',x-y)

但是,這樣寫太麻煩了,沒有總計是小事,假設(shè)有十多個列四則運算怎么辦?
毛利額5 =?
sumx('Sheet1',
? ? var x='Sheet1'[銷量]*'Sheet1'[售價]
? ? var y='Sheet1'[銷量]*'Sheet1'[進價]
return
? ? x-y
)
解釋:將變量定義在迭代函數(shù)里面,迭代函數(shù)本身就是逐行掃描,就代表著當前行

在這個知識點上,《DAX神功》與《The Definitive Guide to DAX》推導(dǎo)的方式不同,《The Definitive Guide to DAX》是以嵌套的概念推導(dǎo),《DAX神功》是以當前行概念推導(dǎo)
接下來我們再看一下毛利額6:
證明:在同一個VAR/Retrun代碼塊之內(nèi),定義的變量可以使用
毛利額6 =?
sumx('Sheet1',
? ? var x='Sheet1'[銷量]*'Sheet1'[售價]
return
? ? x
? ? -
? ? var y='Sheet1'[銷量]*'Sheet1'[進價]
return
? ? y
)
解釋:在迭代函數(shù),定義變量x并輸出? 減去??定義變量y并輸出
這符合規(guī)則:在同一個VAR/Retrun代碼塊之內(nèi),定義的變量可以使用

有爭議的地方在于:《The Definitive Guide to DAX》指出變量在其自身的VAR/Retrun代碼之外不可用?
但是《The Definitive Guide to DAX》中案例舉例是正確的,書中大致意思如下:
但是它的例子并不能說明,自身的VAR/Retrun代碼之外不可用?
因為你并沒有重新定義VAR函數(shù)

書中原文總結(jié),定義在自身VAR/Return之外不可用,VAR/Return中聲明的變量在return結(jié)束后不再可見,引用它會產(chǎn)生錯誤
關(guān)于這個問題,我在PowerBI? 2021.6月版本測試通過,并沒有發(fā)現(xiàn)不可用或引用錯誤:
毛利額7 =?
sumx('Sheet1',
? ? var x='Sheet1'[銷量]*'Sheet1'[售價]
? ? var z=0
return
? ? z
? ? +
? ? var y='Sheet1'[銷量]*'Sheet1'[進價]
return
? ? x-y
)

所以,書中說的這一點是有分歧的,拿出來與大家共同探討,互通有無。
四、當變量做為一張表時
《DAX神功》第1卷第7回: 證明了變量可以是一張表
一班男生 =?
????????var tb1 = FILTER('Sheet1','Sheet1'[性別]="男")
return
????????FILTER(tb1,'Sheet1'[班級]="一班")
Ps:但這只是新建表中對表的篩選。
接下來我們講講在新建列或度量值中如何定義變量為表:
【新建列】
毛利額8 = CALCULATE(sumx(FILTER('Sheet1','Sheet1'[商品] in {"A","B"}),'Sheet1'[銷量]*'Sheet1'[售價]-'Sheet1'[銷量]*'Sheet1'[進價]))

我們現(xiàn)在將【毛利額8】 改寫成變量形式
毛利額8 =?
????????VAR tb1=FILTER('Sheet1','Sheet1'[商品] in {"A","B"})
return
????????CALCULATE(sumx(tb1,'Sheet1'[銷量]*'Sheet1'[售價]-'Sheet1'[銷量]*'Sheet1'[進價]))

之前我們的變量是一個標量值時,它本身就是當前行,不需要篩選。
當你在新建列上使用變量是一張表時,要格外注意,因為新建列是行上下文,需要calculate轉(zhuǎn)換后才可篩選。
名詞解釋:
惰性計算(Lazy Evaluation),又稱懶惰計算、懶漢計算,是一個計算機編程中的一個概念,它的目的是要最小化計算機要做的工作。
VAR就是惰性計算:
<1> 沒有被使用過的變量永遠不會被計算
<2> 當變量完成了首次計算,則它不會在同一范圍內(nèi)被再次計算。
而這個案例,VAR tb1? 只是起到了篩選表功能,并沒有生效于calculate,所以得到了A和B商品毛利額總和21+24=45。 因為它首次使用時已經(jīng)被計算(篩選表A和B商品),所以不會再被Calculate影響,失去了最終的篩選功能。
正確的寫法:
[新建列]
毛利額8 =?
CALCULATE(
????????VAR tb1=FILTER('Sheet1','Sheet1'[商品] in {"A","B"})
return
????????sumx(tb1,'Sheet1'[銷量]*'Sheet1'[售價]-'Sheet1'[銷量]*'Sheet1'[進價])
)
不過,寫成度量值時,你不需要套calculate所以不牽扯這個問題
因為度量值自動將行上下文轉(zhuǎn)換成篩選上下文
【度量值】
毛利額9 =?
????????VAR tb1=FILTER('Sheet1','Sheet1'[商品] in {"A","B"})
return
????????sumx(tb1,'Sheet1'[銷量]*'Sheet1'[售價]-'Sheet1'[銷量]*'Sheet1'[進價])

五、回答網(wǎng)友問題:if如何用在度量值中并使用VAR變量


【1】新建列
新建列1 = if('表1'[性別]="男","先生","女士")
新建列2 =?
????var x = '表1'[性別]
return
? ? IF(x="男","先生","女士")

【2】度量值
度量值1 = MINX('表1',if('表1'[性別]="男","先生","女士"))
度量值2 =?
var x = SELECTEDVALUE('表1'[性別])
return
? ? IF(x="男","先生","女士")
Ps: 關(guān)于總計不顯示的問題 《DAX神功》第1卷第10回 再次講解過

友情提示:《The Definitive Guide to DAX》中關(guān)于變量的案例是有參考價值的,可以開拓你的思路。

《孫興華講PowerBI火力全開》PowerBI必學課程
https://www.bilibili.com/video/BV1qa4y1H7wp
《DAX神功》文字版合集:
https://www.bilibili.com/read/readlist/rl442274
《DAX神功》視頻版合集:
https://www.bilibili.com/video/BV1YE411E7p3
PowerBI(DAX函數(shù))、PowerQuery(M函數(shù))、Python辦公自動化、Python爬蟲、Python數(shù)據(jù)分析、ExcelVBA、WordVBA、AccessVBA、MySQL等等
https://www.bilibili.com/read/cv10222110?