今天,小悅和大家分享一篇國外知名大咖的一篇文章:DAX中“按列排序”的所產生的另一種結果。
Power BI中的“按列排序”功能會導致產生副作用,這些副作用在編寫DAX公式時必須了解。本文介紹了這些副作用以及如何編寫正確的DAX代碼以避免產生錯誤的結果。
按列排序功能:使用來自另一列的值對列的值進行排序。
例如,報表設計員可能希望按一月,二月和三月的順序按名稱顯示月份。因此,按列排序屬性應用“Month Name”列,使用“Month Number”列定義月份名稱的排序順序。這樣可以避免按字母排序得到你不想要的值。
DAX和MDX中的列排序順序
MDX中的查詢會自動從數據模型繼承正確的列排序順序。MDX查詢的結果始終根據“按列排序”設置進行排序。但是,除了基礎數據類型的自然排序順序以外,DAX對列沒有任何隱式排序順序。
因此,DAX查詢必須始終在ORDER BY條件中指定排序順序,這與SQL查詢類似。因為DAX要求將ORDER BY中使用的列作為查詢結果的一部分,所以對BI列進行排序的Power BI視覺總是會生成一個查詢,該查詢至少包括兩列:報表中請求的列和報表中使用的基礎列-按列排序設置。換句話說,按月顯示數據的Power BI視覺圖必須生成一個包含月名稱和月號的查詢。例如,參考Power BI中的以下報告:
DAX生成的查詢如下:
EVALUATE
TOPN (
502,
SUMMARIZECOLUMNS (
ROLLUPADDISSUBTOTAL (
ROLLUPGROUP (
'DATE'[MONTH NAME],
'DATE'[MONTH NUMBER]
), "ISGRANDTOTALROWTOTAL"
),
"SALESAMOUNT", 'SALES'[SALESAMOUNT]
),
[ISGRANDTOTALROWTOTAL], 0,
'DATE'[MONTH NUMBER], 1,
'DATE'[MONTH NAME], 1
)
ORDER BY
[ISGRANDTOTALROWTOTAL] DESC,
'DATE'[MONTH NUMBER],
'DATE'[MONTH NAME]
盡管報告僅顯示月份名稱,但DAX查詢同時包含月份名稱和月份編號。實際上,結果已按月號正確排序。
現在,考慮連接到相同數據模型的Excel中的等效數據透視表,例如使用powerbi.com上的“在Excel中分析”功能。
MDX生成的查詢如下:
SELECT
NON EMPTY
HIERARCHIZE(
{ DRILLDOWNLEVEL(
{ [DATE].[MONTH NAME].[ALL] },
,,
INCLUDE_CALC_MEMBERS
) }
)
DIMENSION PROPERTIES
PARENT_UNIQUE_NAME,
HIERARCHY_UNIQUE_NAME
ON COLUMNS
FROM [MODEL]
MDX查詢僅包含月份名稱。不必指定月份號,因為MDX保證結果中的月份名稱屬性已經按月份號排序了。
DAX查詢中按列排序的副作用
兩列的存在也會對過濾器上下文產生副作用。例如,參考以下方法:
FILTERMONTHNAME :=
ISFILTERED ( 'DATE'[MONTH NAME] )
FILTERMONTHNUMBER :=
ISFILTERED ( 'DATE'[MONTH NUMBER] )
WRONG % MONTHS :=
DIVIDE (
[SALESAMOUNT],
CALCULATE (
[SALESAMOUNT],
ALL ( 'DATE'[MONTH NAME] )
)
)
通過在Power BI和Excel中比較相似報告的結果,可以發現一些差異。
錯誤月份百分比度量在Power BI(左側)中不起作用,因為它始終返回100%,而在Excel(右側)中則正確。
此外,ISFILTERED函數為兩個客戶端中的FilterMonthNumber列提供不同的結果:當選擇月份名稱(左側)時,Power BI始終返回TRUE,而Excel在類似的報告中返回FALSE。原因是DAX在查詢中同時包含兩列–與MDX生成的過濾器上下文相比,這將生成不同的過濾器上下文來評估度量。
最后,當報表使用不帶“月份名稱”的“月份編號”列時,“月份名稱”上的“按列排序”的存在不會引起任何副作用。以下Power BI報告顯示,當在矩陣的行中使用月份號時,只有FilterMonthNumber度量返回TRUE,而不會影響FilterMonthName度量。
使用“按列排序”的度量的黃金法則
為了使使用“按列排序”設置操作列的措施具有可預測的作用,每次刪除或操作過濾器時,最好始終包括“按列排序”設置涉及的兩個列。
因此,如果要在單個列上編寫過濾器測試,如:
ISFILTERED ( 'DATE'[MONTH] )
ISFILTERED ( 'DATE'[MONTH NUMBER] )
最好編寫一個包含兩列的單個表達式,例如:
ISFILTERED ( 'DATE'[MONTH] ) || ISFILTERED ( 'DATE'[MONTH NUMBER] )
如果要在單列上除去過濾器:
ALL ( 'DATE'[MONTH] )
ALL ( 'DATE'[MONTH NUMBER] )
最好編寫一個包含兩列的過濾器:
ALL ( 'DATE'[MONTH], 'DATE'[MONTH NUMBER] )
根據這些最佳實踐進行了重寫,以前的百分比度量如下所示:
CORRECT % MONTHS :=
DIVIDE (
[SALESAMOUNT],
CALCULATE (
[SALESAMOUNT],
ALL ( 'DATE'[MONTH NAME], 'DATE'[MONTH NUMBER] )
)
)
當在矩陣行中使用“月份名稱”時,使用最后一項度量的Power BI報告按月顯示正確的百分比。
結論
當DAX表達式從具有“按列排序”設置處於活動狀態的列中刪除過濾器時,最佳做法是始終將兩個列都包括在ALL函數中(可參考ALL的功能)。為了測試是否對列進行了過濾,最佳做法是在“ 或”條件下包括兩個ISFILTERED函數,測試“按列排序”設置中涉及的兩個列。
獲取案例文件
如果您喜歡該文章,並想要獲取該文章源文件的朋友們,留言獲取。
往期推薦
● 新DAX功能:CONVERT and REMOVEFILTERS
●【2019】10月份(廣州站)Power BI 線下活動報名
技術交流
1.Power BI免費下載:http://www.yeacer.com/
Microsoft Power BI Desktop中文最新版:下載地址
2.歡迎加入的Power BI技術群,目前正在學習階段,有興趣的朋友可以一起學習討論。
Power Data技術交流群:702966126 (驗證注明:博客園Power BI)
更多精彩內容請關注微信公眾號:悅策PowerBI
如果您覺得閱讀本文對您有幫助,請點一下“推薦”按鈕,您的“推薦”將是我最大的寫作動力!歡迎各位轉載,作者博客:https://www.cnblogs.com/yeacer/