羅叔講DAX:ALL 與 REMOVEFILTERS

  • 2019 年 10 月 6 日
  • 筆記

在 DAX 中有一個神奇的函數 ALL,被譽為 DAX 聖經的書中有專門的多頁篇幅來講解這個 ALL 以及其相關係列。在 2019年9月 DAX中又新增了一個函數 REMOVEFILTERS,那麼,ALL 到底是怎麼回事?與 REMOVEFILTERS 到底有何不同?如果你看 DAX聖經 你需要看很久,而羅叔則讓你秒懂,永遠不會錯。

羅叔是宗旨是在理解透徹 DAX 後,告訴初學者以及業務用戶更容易識記的規律以讓大家不至於陷入技術細節。因為,BI 是業務驅動的,而不是技術驅動的。

市場佔有率 – 第一次用 ALL

先看一個業務問題:市場佔有率,其 DAX 計算為:

其中,

KPI.MarketShare% =  [KPI.Sales] / CALCULATE( [KPI.Sales] , ALL( 'Product'[類別] ) )

這是第一次接觸 ALL 的合理場景。

其業務含義為:當前所選產品類別的銷售額 占 所有產品類別的銷售額,即:某產品類別的市場佔有率。

這裡的 ALL 將幫助我們似乎達到一個效果:忽略(清除)了外界的篩選並返回所有的類別。

注意這裡的用詞:似乎 和 效果。這裡涉及到兩件事:忽略(清除)篩選 和 返回所有類別。

我們等下再來看這兩件事。先看另一個PowerBI中的有意思的現象。

全選 與 全不選

首先,我們先做一個度量值,如下:

DAX - 產品類別 是否 被篩選 = ISFILTERED( 'Product'[類別] )

其含義不言而喻。我們拖拽一個切片器如下:

現在問題來了,如果點擊 全選 或 全不選(點擊兩次全選即可切換為全不選)會是什麼結果。在看答案前,很多人或猜測:

  • 猜測全選時,返回 TRUE,對嗎?
  • 猜測全不選時,返回 FALSE,對嗎?

這種猜測很自然,但結果讓你驚訝:

首先,先看全不選的時候,如下:

其次,來看全選的時候,如下:

居然也是 FALSE。於是得到一個很奇葩的結論:全選與全不選都是全不選。因此,這種全選表面上點擊了全選按鈕,而實際上,相當於點擊了清除按鈕,如下:

也就是說:點擊全選等價於點擊清除

奇葩的事情並沒完,羅叔帶你繼續飛。

一個個全選

這次我們一個一個點擊選擇,如下:

繼續點擊 傢具,如下:

我去,什麼鬼?居然返回了 TRUE。

強調一遍,當一個個選擇直到全選時,返回了 TRUE。

到底有沒有選

來看兩個圖:

上下兩圖完全一致,但篩選結果卻完全不同。那到底選了沒有?

總結規律

以下直接總結規律,你可以重新回看上述內容或自己做實驗:

  • 初始狀態,沒有選擇任何元素,也就是某列沒有被篩選。
  • 直接全不選與直接全選等價,沒有選擇任何元素,也就是某列沒有被篩選。
  • 直接全選與直接全不選等價,沒有選擇任何元素,也就是某列沒有被篩選。
  • 清除選擇回到初始狀態,沒有選擇任何元素,也就是某列沒有被篩選。
  • 逐個選擇直至全選,選擇了所有元素,某列被篩選。

其狀態變化圖如下:

再仔細觀察下 PowerBI 的切片器控制項,如下:

識記 DAX 函數

將上面的經驗與 DAX 函數結合,便可以得到這樣的準確用詞以及規律:

  • 無函數,對應於【初始化】,無篩選,ISFILTERED 返回 FALSE。
  • ALL,對應於【直接全選】與【直接全不選】等價,無篩選,ISFILTERED 返回 FALSE。
  • FILTER( ALL( T[C] ) , TRUE() ),對應於【逐個全選】,有篩選,ISFILTERED 返回 TRUE。
  • REMOVEFILTERS,對應於【清除選擇】,無篩選,ISFILTERED 返回 FALSE。

其中,第三條可能有點突然,我們來觀察由此構建的 DAX 表達式,如下:

DAX - 產品類別 是否 被篩選 = ISFILTERED( 'Product'[類別] )    DAX - ALL = CALCULATE( ISFILTERED( 'Product'[類別] ) , ALL( 'Product'[類別] ) )    DAX - FILTER.ALL = CALCULATE( ISFILTERED( 'Product'[類別] ) , FILTER( ALL( 'Product'[類別] ) , TRUE() ) )    DAX - REMOVEFILTERS = CALCULATE( ISFILTERED( 'Product'[類別] ) , REMOVEFILTERS( 'Product'[類別] ) )    DAX - VALUES = CALCULATE( ISFILTERED( 'Product'[類別] ) , VALUES( 'Product'[類別] ) )

對應的結果,如下:

尤其值得注意的是,DAX – FILTER.ALL 版本返回的是被篩選的 TRUE,由於 FILTER 是一個迭代函數,要對某列逐行考察,就如同逐個選擇,因此,是被篩選的。

總結

至此可以得到非常清晰的識記方式:

  • ALL – 全選,與全不選以及清除篩選等價。
  • 當 ALL 位於 FILTER 等函數內時,全選後再被迭代判斷而篩選,因此,是被篩選的。
  • REMOVEFILTERS – 清除選擇,與全選以及全不選等價。
  • VALUES – 當前元素(們),形式為一個列構成的表。

這樣,就可以清楚得記憶這個問題的答案了,其中DAX程式碼均以給出,大家可以自行嘗試,示例數據為通用文件,可在入門星球獲取,祝大家玩得開心。

本文內容系 DAX基礎 部分,更多 DAX基礎 學習請進入 DAX基礎 星球,系統化學習。