DAX專題12: RANKX() and TOPN()-讀書筆記(20)

本章介紹RANKX()和TOPN()函數(shù),這兩個(gè)函數(shù)在解決排名問題上有些相似,但處理過程和技術(shù)不一樣,我們介紹這兩個(gè)函數(shù),解決這樣兩個(gè)問題:
?? 哪些產(chǎn)品最暢銷?
???前10名暢銷產(chǎn)品的銷量是多少?
一、關(guān)于 RANKX() 和 TOPN()?
RANKX函數(shù)是一個(gè)返回標(biāo)量值(就是一個(gè)值)的函數(shù),即在可視化對(duì)象中做為一個(gè)值呈現(xiàn)出來。TOPN是一個(gè)表函數(shù),TOPN返回的表是按特定指標(biāo)(如總銷售額,總利潤)比較以后滿足條件的多行表(如果指定指標(biāo)取前1名,且第1名無重復(fù),那就只有一行)。我們知道:返回值的函數(shù)可以單獨(dú)寫進(jìn)度量值,但表不能當(dāng)作度量值使用或者說不能把一個(gè)表作為度量值的唯一參數(shù)用。但我們可以將TOPN返回的表作為其他函數(shù)的參數(shù)使用,現(xiàn)實(shí)中通常是作為CALCULATE()的第二參數(shù)(當(dāng)成篩選表使用)。
這樣寫度量值是錯(cuò)誤的:
Invalid Measure 1 = TOPN(10,Products)
Invalid Measure 2 = FILTER(ALL(Products),Products[Category]="Bikes")
這兩個(gè)公式都返回表,因此像這樣使用它們作為度量值是錯(cuò)誤的。要讓度量值公式生效,公式必須返回單個(gè)值。但這并不意味著不能在度量值中使用表函數(shù)。接下來的三個(gè)度量都包含表函數(shù),但它們都返回值,都是正確的度量值寫法:
Valid Measure 1 = RANKX(ALL(Products),[Total Sales])
Valid Measure 2 = CALCULATE([Total Sales], TOPN(10,Products))
Valid Measure 3 = COUNTROWS(FILTER(ALL(Products),Products[Category]=?
"Bikes"))
返回表的函數(shù)可以作為其它函數(shù)的參數(shù),只要這個(gè)參數(shù)類型是表就可以。
二、RANKX() 值函數(shù)
??語法:RANKX(table,expression,[value],[order],[ties])
RANKX前兩個(gè)參數(shù)是必選參數(shù),后三個(gè)參數(shù)是可選參數(shù),本章只介紹前兩個(gè)必選參數(shù),后三個(gè)參數(shù)的用法大家可以自行了解。
盡管RANKX不是表函數(shù),但它的第一個(gè)參數(shù)必須是一個(gè)表,DAX語言中很多函數(shù)在使用行上下文時(shí)都使用表做為第一參數(shù)。也有函數(shù)是例外,像UNION函數(shù)。
?? 不用函數(shù)如何取得前銷售前10名
我們先在報(bào)表視圖界面插入一個(gè)表,并將產(chǎn)品編碼[ProductKey]、產(chǎn)品名稱[ProductName]和銷量[Total Sales]字段放到表的列上,對(duì)[Total Sales]進(jìn)行降序排列。

表中顯示所有產(chǎn)品銷售為29358677元,我們可以對(duì)這個(gè)表進(jìn)行一個(gè)篩選,先出銷售10名。操作方法:在篩選區(qū)域選擇按銷售額前10名篩選。這個(gè)示例我們使用了可視化篩選的功能,這與TOPN函數(shù)函數(shù)操作方式不一樣。

在可視化篩選中,我們可以選擇不同的指標(biāo)放在篩選的值區(qū)域做為篩選的標(biāo)準(zhǔn),這挺有趣的,因?yàn)樽鰹楹Y選值的度量值或列可以不是矩陣中的度量值或列。上個(gè)例子中我們是按銷量篩選的,我們也可以按毛利潤進(jìn)行篩選前10,如下圖

?? 使用RANKX 獲取銷售前10名
使用RANKX 我們可以獲得每個(gè)產(chǎn)品的銷售排名,RANKX的計(jì)算邏輯是拿一個(gè)值和其它多個(gè)值比較,確定出這個(gè)值的排名(位置)。
第一參數(shù)是一個(gè)表,比如按產(chǎn)品、按顧客排名,就要用產(chǎn)品表或客戶表,計(jì)算度量值在某個(gè)表的排名時(shí)這個(gè)表不能被初始篩選或者只能被指定的字段篩選),這樣才能保證是在想要的范圍內(nèi)進(jìn)行比較排名,我們可以使用ALL函數(shù)清除某些字段的篩選或清除表的篩選。
按RANKXA語法我們寫個(gè)度量值:Product Rank Wrong = RANKX(Products,[Total Sales])

為什么排名都是1呢?NOTE: 分析可視化對(duì)象的計(jì)算結(jié)果是否正確,對(duì)于DAX用戶來說分析計(jì)算的過程是關(guān)鍵,有機(jī)會(huì)就練練。
計(jì)算結(jié)果不正確時(shí),首先我們要懷疑是篩選出了問題,可能不是所有的錯(cuò)誤都是篩選導(dǎo)致的,從經(jīng)驗(yàn)來看大部分問題基本上都可以歸咎到篩選上。我們來還原一下公式的計(jì)算過程,以矩陣行字段第一行為例,RANKX的作用是找出第一行產(chǎn)品名稱為:product 312 的總銷量,與其它產(chǎn)品名稱的銷量比較得到一個(gè)排名。為了更好理解這個(gè)問題,我們作一個(gè)測試度量值
Test =? COUNTROWS(Products),把它放到矩陣中

矩陣中TEST度量值是產(chǎn)品表被矩陣行字段(ProductName)篩選的行數(shù),Product表放到矩陣中后矩陣行字段把每個(gè)產(chǎn)品名稱對(duì)應(yīng) 的產(chǎn)品表的行都篩選出來了。這表明:Product放在函數(shù)中做為度量值參數(shù)時(shí),表受到矩陣初始篩選的影響,整個(gè)度量值也受到了影響,表格被矩陣的行字段都篩選成了一行,所以計(jì)算排名時(shí)[TOTAL SALES]只看到了一行數(shù)據(jù)的表,沒有其它值跟這個(gè)表的總銷量比較了,就全部變成了第1名。
這時(shí)我們需要ALL函數(shù)來幫忙,清除掉對(duì)Product的篩選,這樣矩陣行字段不能篩選Product表,對(duì)于矩陣行字段每個(gè)產(chǎn)品的銷量都要和整個(gè)Product表的產(chǎn)品銷售做比較,就能得到正確的排名。

正確寫法:Product Rank = RANKX(ALL(Products),[Total Sales])
? ? ?Product Rank = RANKX(ALL(Products[ProductName],),[Total Sales])
三、復(fù)習(xí)一下上下文轉(zhuǎn)換? Filter Context Revisited
上節(jié)提到了一個(gè)非常重要的觀點(diǎn),需要重申一下并加以擴(kuò)展對(duì)它的認(rèn)識(shí):函數(shù)內(nèi)部使用的"參數(shù)表"會(huì)受到來自視覺對(duì)象篩選的影響,函數(shù)的"參數(shù)表"并不是使用整個(gè)表,這個(gè)表是可視化對(duì)象篩選的后的表副本(例如矩陣的行字段篩選后的表)。如果您使用不讓可視化對(duì)象篩選的整個(gè)表,則必須要用ALL函數(shù)清除可視化對(duì)象對(duì)表的篩選,
像Product Rank = RANKX(ALL(Products),[Total Sales])就是清除了外部篩選器(初始篩選器)對(duì)產(chǎn)品表的篩選。
度量值和聚合函數(shù)也受到來自可視化對(duì)象的篩選影響,下圖是第16章的一個(gè)自定義時(shí)間智能公式

第7行上的ALL()函數(shù)清除了來自可視化對(duì)象(矩陣行)對(duì)Calendar的篩選,因此ALL('Calendar')是Calendar表的一個(gè)未經(jīng)篩選的副本。上面的代碼中FILTER()函數(shù)正在遍歷Calendar表(參數(shù)1)的一個(gè)全部行,第3、9和10行中MAX()每次都不是尋找整個(gè)列的最大值,而是通過可視化篩選后的列的最大值。第5行上的[Total Sales]度量值也被可視化對(duì)象篩選(當(dāng)然,該度量值也由CALCULATE()內(nèi)的篩選函數(shù)篩選)。
我們再回來看看上一節(jié)的矩陣排名。既然公式已經(jīng)可以正確運(yùn)行,并且你也理解了它的工作過程和原理,那么讓我們看看篩選在兩種場景下的行為。首先,下圖顯示了在ProductKey而不是[Total Sales]降序排序時(shí)發(fā)生了什么?

上圖的顯示方式有別于EXCEL。RANKX函數(shù)只對(duì)每個(gè)產(chǎn)品按銷售額的多少進(jìn)行排名,至于產(chǎn)品以什么順序排序它并不關(guān)心,我們可以做一個(gè)切片器和一個(gè)卡片圖并把剛才的排名度量值放到卡片圖中,當(dāng)你選擇某一個(gè)產(chǎn)品時(shí),卡片圖顯示的是這個(gè)產(chǎn)品在全部產(chǎn)品中的名次。

這個(gè)例子有點(diǎn)意思,列Products[ProductName]都沒有在RANKX()公式中使用,但是使用該列做為切片器是有效的。為什么呢?因?yàn)槲覀儧]有Products[ProductName]使用清除篩選,列Products[ProductName]可以篩選整個(gè)Products表。當(dāng)我們在切片器上選擇了一個(gè)產(chǎn)品名稱時(shí),產(chǎn)品表就只剩下一行,只有一個(gè)產(chǎn)品鍵,列Products[ProductKey]在RANKX()公式中使用了,因此RANKX度量值可以正常運(yùn)行??偠灾珼AX也不是很復(fù)雜,但學(xué)好它也確實(shí)不是件容易事兒。
四、TOPN()? 表函數(shù)
與RANKX相比,TOPN函數(shù)更直觀一些,更容易理解。
語法:
TOPN(<N_Value>, <Table>, <OrderBy_Expression>, [<Order>[, <OrderBy_Expression>, [<Order>]]…])?

返回值:
一個(gè)由 Table 的前 N 行組成的表,或者如果 N_Value 為 0(零)或更小,則為空表。 行不按任何特定順序排序。
備注:
? 如果在表的第 N 行 order_By 值存在關(guān)聯(lián),則返回所有關(guān)聯(lián)的行。 因此,在第 N 行有關(guān)聯(lián)時(shí),函數(shù)可能返回多于 n 行。
? 如果 N_Value 為 0(零)或更小,則 TOPN 將返回一個(gè)空表。
? TOPN 不保證結(jié)果的任何排序順序。
? 可以使用多列做為TOPN的篩選條件,重復(fù)第三參數(shù)和第四參數(shù)。如
Sales from Top 10 Products =?
? ? CALCULATE ([Total Sales],
? ? ? ? TOPN (10, Sales,Sales[SalesPrice],0,Sales[SalesRemainPrice],0)
? ? )
? 在已計(jì)算的列或行級(jí)安全性 (RLS) 規(guī)則中使用時(shí),不支持在 DirectQuery 模式下使用此函數(shù)。
?? 本章向大家展示一下TOPN前兩個(gè)必選參數(shù)的使用,后面幾個(gè)可選參數(shù)大家自己有時(shí)間再深入學(xué)習(xí)吧。
TOPN是一個(gè)表函數(shù),這通常用在CALCULATE函數(shù)中做為篩選表使用(做為CALCULATE的第二參數(shù))。比如我們想計(jì)算銷量最好的前10名的產(chǎn)品的銷售額時(shí),可以使用TOPN來寫個(gè)度量值:
Sales from Top 10 Products =? CALCULATE ([Total Sales],
? ? ? ? TOPN (10, Products,[Total Sales]))
放個(gè)切片器到報(bào)表視圖,把Category進(jìn)來;再做個(gè)卡片圖,把度量值放進(jìn)來。當(dāng)切片器什么也不選時(shí),卡片圖得到的數(shù)值和我們手工篩選出銷售前10的產(chǎn)品的總額相同。

NOTE 1
?TOPN()是一個(gè)表函數(shù),因此最常見的用法是作為CALCULATE()函數(shù)中的篩選參數(shù)。
Sales from Top 10 Products = CALCULATE ([Total Sales],
? ? ? ? TOPN (10, Products,[Total Sales]))
Note 2?
注意,在上面的公式中,這次ALL(Products)沒有在TOPN()中使用。這里不需要它,因?yàn)榭ㄆ瑘D(下圖右)中沒有篩選條件。這既沒有對(duì)也沒有錯(cuò);你如何處理它取決于你想做什么,你可以在下面的表格中(下圖左)使用這個(gè)新的度量值。

前10名銷量中,Accessories,Bikes,Clothing各銷售了多少一目了然。
因?yàn)镻roducts表沒有使用ALL函數(shù),度量值要受到視覺對(duì)象的篩選影響。在上面的表格中,可以看到按類別劃分的前10名中各產(chǎn)品的總銷售額。如果在度量中使用ALL(Products),度量值就忽略來自表格(或其它視覺對(duì)象的)任何篩選條件了。
反之,如果在TOPN中使用ALL(Products),那它返回的總是前10個(gè)產(chǎn)品的銷售總額,把可視化中Products表的篩選統(tǒng)統(tǒng)不考慮。
Sales from Top 10 ALL Products =?CALCULATE ([Total Sales],
? ? ? ? TOPN (10, ALL(Products),[Total Sales]))
