Power BI之DAX神功:第3卷第17回 擴(kuò)展表中的上下文轉(zhuǎn)換
官方解釋:擴(kuò)展表所有列的行上下文都會(huì)被轉(zhuǎn)換成等效的篩選上下文。
不要被文章的標(biāo)題和官方解釋嚇到,擴(kuò)展表什么樣,你也改變不了!比如說(shuō):孫興華今年21歲,你生氣,你說(shuō)不行,孫興華不能是21歲,那你也讓我變不成18歲呀!
這一課的重點(diǎn)是告訴我們:上下文轉(zhuǎn)換也許比行上下文更消耗性能!
提到上下文轉(zhuǎn)換,我們首先想到Calculate和CalculateTable,但是我們之前講過(guò)的一些時(shí)間智能日期函數(shù)FIRSTDATE、LASTDATE、FIRSTNONBLANK、LASTNONBLANK 等等,它們內(nèi)部都有隱藏的Calculate實(shí)現(xiàn)上下文轉(zhuǎn)換。
《DAX神功》答網(wǎng)友問(wèn)12.為什么LastDate與Max結(jié)果不同? 中我們就做了詳細(xì)證明
不要因?yàn)橐恍┲v師告訴你們盡量不要新建列,要用度量值。你就認(rèn)為行上下文速度慢,轉(zhuǎn)換成篩選上下文速度快!不一定!
要我說(shuō),你隨心所欲就好,就像我用VBA一樣,20多年前老師在學(xué)校讓我定義數(shù)據(jù)類型,學(xué)校電腦奔騰133MHz+16M SDRAM定義什么都慢,機(jī)器就不行!現(xiàn)在我的電腦跟你們比還是很差A(yù)MD2200G+16G DDR4 但是在VBA中是否定義數(shù)據(jù)類型我還是沒(méi)感覺(jué)出區(qū)別來(lái)。
今年剛上市的3A大作也許最低顯卡要求1650,推薦3080。但是我告訴你10年之后,主流集成顯卡都能玩這款3A(別比幀數(shù),我指的是1080p下能流暢的玩)。我現(xiàn)在用的AMD2200G集成Vage8配上雙通道DDR4內(nèi)存可以達(dá)到80% 1030顯卡的水平,10年前的游戲基本都能玩。
游戲可能10年后你因?yàn)楫嬞|(zhì)問(wèn)題或者有后續(xù)新作就不喜歡前作了,Excel、DAX和游戲還不一樣!它們的生命周期也許是30年至50年!甚至更久!
DAX不是SQL,數(shù)據(jù)峰值也就百萬(wàn)行數(shù)據(jù)。你現(xiàn)在絞盡腦汁研究的優(yōu)化,會(huì)被時(shí)間和硬件埋沒(méi)!這話今天你可能不信,Excel不淘汰,DAX就不會(huì)淘汰,10年之后如果有人翻出這篇文章,秒懂!
Ps:并不代表DAX優(yōu)化沒(méi)用,只是對(duì)于你來(lái)說(shuō),付出和回報(bào)是否成比例,由你個(gè)人決定。
一、上下文轉(zhuǎn)換


《DAX神功》答網(wǎng)友問(wèn)05 返回表的迭代函數(shù)你應(yīng)該注意什么?我們證明了:
ADDCOLUMNS:相當(dāng)于整容,例如你長(zhǎng)了兩只眼睛,整容可以讓你變成3只,但你還是你。
SELECTCOLUMNS:相當(dāng)于克隆再整容,克隆你再整容成3只眼,長(zhǎng)的一樣,但是那不是你。
我們今天的測(cè)試用哪個(gè)都一樣,我們就選擇ADDCOLUMNS吧!

上圖中學(xué)生表這樣的情況很普遍吧,同名張三,但是學(xué)號(hào)不同,就是兩個(gè)人。
學(xué)生表是1端表,他的學(xué)號(hào)是主鍵,主鍵不為空不重復(fù)!學(xué)PowerBI之前我讓大家去學(xué)Access基礎(chǔ)篇s01開頭的集數(shù),沒(méi)坑你們。我們使用學(xué)生表的學(xué)號(hào)(主鍵)連接成績(jī)表的學(xué)號(hào)(外鍵)構(gòu)成一對(duì)多關(guān)系。
如果說(shuō)學(xué)號(hào)是唯一值(廢話!主鍵不為空不重復(fù)它肯定是唯一值),我就返回學(xué)號(hào)對(duì)應(yīng)的姓名。同理,學(xué)號(hào)是唯一值返回學(xué)號(hào)!度量值如下:
關(guān)于IF + HASONEVALUE?原理詳見《DAX神功》第2卷第19回
這樣的寫法:PowerBI 2021.10月版測(cè)試通過(guò),如果版本太舊,可能不支持此語(yǔ)法

因?yàn)槎攘恐当旧硎呛Y選上下文,if語(yǔ)句生成行上下文,我們需要套上Calculate做轉(zhuǎn)換
返回結(jié)果:

上面的方法才是正解!《The Definitive Guide to DAX》中將IF(HASONEVALUE(字段名), VALUES(字段名))的方法替換成了SELECTEDVALUE(字段名)。在《DAX神功》第2卷第19回我們的確講過(guò)這樣的替換,但是在這里,不行!你只能確定主鍵不為空不重復(fù),其它列你確定不了!
如果我們這樣使用代碼:
返回結(jié)果:直接報(bào)錯(cuò)!因?yàn)樾彰兄貜?fù)!

當(dāng)初我講完《火力全開》后,很多講師來(lái)抬扛,理由是權(quán)威指南說(shuō)什么,國(guó)外文獻(xiàn)說(shuō)什么!
別管別人說(shuō)什么,在不同的環(huán)境下有不同的方案,任何人寫出的代碼也不可能適配所有的環(huán)境。既然這樣,只要對(duì)方能解決自己的案例,就沒(méi)有問(wèn)題,談不上對(duì)錯(cuò)。
最無(wú)知的一句話:你這個(gè)代碼我換一個(gè)表就不行了!
上面講的這些,就是上下文轉(zhuǎn)換!將行上下文轉(zhuǎn)換成了篩選上下文,但是轉(zhuǎn)換過(guò)程中,你有多少個(gè)列,就相當(dāng)于有多少個(gè)篩選器,讓這些列可以篩選。你的列越多,硬件開銷就越大,時(shí)間就越久。所以說(shuō),使用行上下文和轉(zhuǎn)換成篩選上下文誰(shuí)的開銷大,是依據(jù)情況而定的。
二、理解行上下文,一定要知道Excel工作表函數(shù)Vlookup原理
返回結(jié)果:

我攤牌了,這就是行上下文!ADDCOLUMNS給成績(jī)表添加列,通過(guò)RELATED函數(shù)獲取這一行對(duì)應(yīng)的姓名和學(xué)號(hào)。那你知道RELATED函數(shù)是根據(jù)誰(shuí)把姓名和學(xué)號(hào)1這兩列生成的嗎?答案是:成績(jī)表中的外鍵(學(xué)號(hào)),對(duì)!行上下文只考慮這一列!
說(shuō)清楚行上下文,我們還得用VBA的方式來(lái)說(shuō):
就好比咱們?cè)赩BA里面的For循環(huán)、Do While循環(huán)、數(shù)組、字典....
例如有如下兩張表,我現(xiàn)在說(shuō)的是VBA,這兩張表可不需要連線!大家腦子要轉(zhuǎn)過(guò)來(lái)!

現(xiàn)在想將表1中的電話V到表2中,Vlookup函數(shù):找什么,在哪列里找,返回找到的第幾列。Vlookup是人家寫好的函數(shù),你拿來(lái)用,沒(méi)見過(guò)哪位講師將底層函數(shù)拿出來(lái)講代碼的吧?那為什么DAX函數(shù)要講原理?答案:商業(yè)化!
為了更深入的理解行上下文,我們使用VBA舉例:
友情提示:我會(huì)用find函數(shù),我需要先舉一個(gè)極端例子,顯示出速度慢!
返回結(jié)果:

我們從表2的B列第2行開始,姓名是張三,我們將張三在表1中逐行去找,找到了就返回張三對(duì)應(yīng)的電話,沒(méi)找到就返回空。接下來(lái)再找表2的B列第3行,還是這么找。
你試想一下,以王五為例,王五在表2的第1048576行,得到王五的姓名后,我要將王五在表1中每一行進(jìn)行查找,又在表1的1048576行找到了它。我一共循環(huán)了1048576*2次。逐行掃描就是行上下文。
再看看字典:
當(dāng)我們使用字典時(shí),姓名是Key,電話是Value。(因?yàn)槭桥e例,我們假設(shè)沒(méi)有重復(fù)姓名),我們將表1中的姓名和電話存入字典。只需要找表2中的姓名在不在字典中,在就返回對(duì)應(yīng)的電話,不在就返回空。其實(shí)字典更像Vlookup。(當(dāng)然Vlookup函數(shù)底層代碼會(huì)比我這個(gè)寫的要復(fù)雜的多)
很久很久以前,手機(jī)沒(méi)有普及時(shí),我們將電話號(hào)碼記在本子上,打電話用座機(jī),在本子上找號(hào)碼。如果本子上只有你爸媽,那沒(méi)問(wèn)題!如果你的本子上有1萬(wàn)人,你很難快速找到你要找的人。即便你的本子上使用了漢語(yǔ)拼音姓氏排序也需要時(shí)間。我記得2000年以前通信公司出《大黃頁(yè)》這種書,就是按拼音排序企業(yè)名稱,對(duì)應(yīng)有企業(yè)電話。說(shuō)白了就是文字版的114查號(hào)臺(tái)。
80、90年代我就是在本子上找到電話后,去搖對(duì)方電話號(hào)碼!

錯(cuò)了。。。。上面這是我前世用過(guò)的電話。。。我今生第一次用的電話是轉(zhuǎn)盤的

當(dāng)初我第一次見到真電話時(shí),不知道打給誰(shuí),因?yàn)檎J(rèn)識(shí)的人都沒(méi)有電話?,F(xiàn)在除了工作電話之外,我也不知道打給誰(shuí),因?yàn)檎J(rèn)識(shí)的人都挺忙。
現(xiàn)在我們不用電話本了,我們手機(jī)中存著電話,而且基本都有免費(fèi)云端做備份,手機(jī)丟了也能找回電話備份。手機(jī)上就算有10萬(wàn)人,你輸入姓名就可以立即查找。
這就是行上下文!比如:你問(wèn)我張三、李四、王五的手機(jī)號(hào)是多少,我在手機(jī)上輸入張三,把手機(jī)號(hào)抄下來(lái),然后再查李四.....
總結(jié):到底是行上下文快還是轉(zhuǎn)換上下文快?具體問(wèn)題具體分析!沒(méi)有固定答案!104萬(wàn)行只有一列的表,轉(zhuǎn)換上下文有可能快!104萬(wàn)行10列的表,一定行上下文快!因?yàn)檗D(zhuǎn)換上下文篩選每一個(gè)列,而行上下文只看主鍵或外鍵那個(gè)列。
主鍵和外鍵是數(shù)據(jù)庫(kù)知識(shí)!我在《火力全開》首集就告訴大家,一定要去看Access基礎(chǔ)篇S01開頭的內(nèi)容。

《孫興華講PowerBI火力全開》PowerBI必學(xué)課程
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辦公自動(dòng)化、Python爬蟲、Python數(shù)據(jù)分析、ExcelVBA、WordVBA、AccessVBA、MySQL等等
https://www.bilibili.com/read/cv10222110?