DAX:概述ALL函數

簡單的說,當ALL用作表函數時,忽略應用到表上的任何過濾器,並返回數據表;當ALL用作CALCULATE和CALCULATETABLE函數中修飾器時,ALL函數從擴展表中移除已經應用的過濾上下文。

注意自動存在(auto-eixist)對ALL()函數的影響。

正常情況下,包含 ALL() 函數的 DAX 表達式,會忽略已應用到表或指定列上的任何過濾器。但是,由於auto-exists機制的存在,在某些特殊的情況下,事實並非總是如此。自動存在可以優化過濾,以減少某些 DAX 查詢所需處理的數據量。

自動存在導致ALL() 出現意外結果的情況是:在同一表中的兩個或更多列上進行過濾(例如使用切片器),並且在同一個表上有一個使用 ALL() 的度量(Measure)。在這種情況下,自動存在會把多個過濾器合併爲一個,對現有的數據進行過濾,使得ALL()只能對合並之後的值組合進行過濾。 由於DAX會首先合併數據,然後再根據合併之後的值組合重新計算度量,因此,計算的結果是基於篩選值(即合併之後的值)而不是預期的所有值。

換句話說,auto-exist會自動應用過濾器,當ALL()用作CALCULATE或CALCULTETABLE的修飾器時,產生的效果相當於auto-exist把額外的過濾器添加到CALCULATE或CALCULTETABLE函數中。

一,ALL函數的定義

ALL 函數用於清除表上的所有過濾器,返回表中的所有行,或者一列的所有值,適用於對錶中的所有行進行彙總計算。注意,此函數只能用於基礎表(base table),不能用於表表達式或列表達式。

ALL( [<table> | <column>[, <column>[, <column>[,…]]]] )  

ALL 函數,用於移除應用到表或列上的過濾器上下文,跟 REMOVEFILTERS 函數的作用相同。 當在 CALCULATE 或 CALCULATETABLE 的過濾器參數中直接調用時,不會返回任何數據表,僅用於從過濾器上下文中刪除所有過濾器。

以下注釋在使用 ALL 作爲表表達式時有效:

  • 使用表參數,ALL 返回表的所有行,包括任何重複的行。
  • 使用單個列參數,ALL 返回該列的所有唯一值。
  • 使用兩個或多個列參數,ALL 返回多個列中值的所有唯一組合。
  • 在每種情況下,ALL 都會在結果中包含爲無效關係生成的額外空白行。

二,深入理解ALL函數

在DAX中,下面兩個Measure是完全相同的。RedSalesCompact是布爾過濾器,而RedSalesExtended是擴展語法結構。通常RedSalesCompact會被翻譯成(translate)擴展語法,也就是說,CALCULATE的過濾器是table。

RedSalesCompact :=
CALCULATE (
    [SalesAmount],
    Product[Color] = "Red"
)
 
RedSalesExtended :=
CALCULATE (
    [SalesAmount],
    FILTER ( ALL ( Product[Color] ), Product[Color] = "Red" )
)

1,計算百分比

計算百分比的常見做法是將給定度量除以刪除某些過濾器的相同度量。 例如,針對所有顏色的銷售額百分比的正確表達式如下所示:

PctOverAllColors :=
DIVIDE (
    [SalesAmount],
    CALCULATE (
        [SalesAmount],
        ALL ( Product[Color] )
    )
)

這個Measure的含義可以描述爲:ALL 返回一個包含所有顏色的表; 此表表示要在 CALCULATE 的新過濾器上下文中使用的有效顏色。 強制所有顏色可見等同於從顏色列中刪除任何和所有過濾器。

這段描述分爲兩段,兩端都是錯誤的,並不是說描述是完全錯誤的。它在大多數時候都是準確的,但並非總是如此。

上面 PctOverColors 度量中 ALL 行爲的正確描述確實簡單得多:ALL removes any active filters from the Color column.

在正確的描述中,沒有關於 ALL 結果的陳述,事實上,ALL不返回表,並且在包含所有值的表和刪除過濾器之間沒有等價關係。事實要簡單得多:過濾器被移除。 乍一看,這是一個非常迂腐的細節。 但是,當用於更復雜的 DAX 表達式時,這種微小的差異可能會產生截然不同的結果。

2,計算已經出售的產品

例如,讓我們考慮這兩個度量:NumOfProducts 計算產品總數,而 NumOfProductsSold 僅計算已售出的產品,利用表過濾。

NumOfProducts :=
DISTINCTCOUNT ( Product[ProductName] )
 
NumOfProductsSold :=
CALCULATE (
    [NumOfProducts],
    Sales
)

NumOfProducts 很簡單,而 NumOfProductsSold 需要額外的 DAX 知識,因爲它基於表擴展。 因爲表被用作 CALCULATE 中的過濾器參數,所以過濾器上下文包含 Sales 的擴展版本的所有列。

DEFINE
    MEASURE Sales[NumOfProducts] = DISTINCTCOUNT ( Product[Product Name] )
EVALUATE
ROW (
    "NumOfProducts", [NumOfProducts],
    "NumOfProductsSold", CALCULATE ( [NumOfProducts], Sales )
)

執行的結果是:

  • NumOfProducts: 2,517
  • NumOfProductsSold: 1,170

在存在過濾上下文的情況下,兩種度量都將它們的計算限制在當前過濾上下文中。 例如,通過添加一個過濾紅色產品的外部 CALCULATETABLE,查詢變爲:

DEFINE
    MEASURE Sales[NumOfProducts] =
        DISTINCTCOUNT ( Product[Product Name] )
EVALUATE
CALCULATETABLE (
    ROW (
        "NumOfProducts", [NumOfProducts],
        "NumOfProductsSold", CALCULATE ( [NumOfProducts], Sales )
    ),
    'Product'[Color] = "Red"
)

執行的結果是:

  • NumOfProducts: 99
  • NumOfProductsSold: 51

到目前爲止,一切都按預期進行。 如果需要根據總計計算當前上下文中的值,會發生什麼情況? 例如,紅色產品的數量除以產品總數,紅色產品的銷售數量與銷售的產品總數之比,生成此報告:

 可以這樣編寫代碼:

PercOfProducts =
DIVIDE (
    [NumOfProducts],          -- Number of products
    CALCULATE (
        [NumOfProducts],      -- Number of products
        ALL ( Sales )         -- filtered by ALL Sales
)
 
PercOfProductsSold =
DIVIDE (
    CALCULATE (
        [NumOfProducts],      -- Number of products
        Sales                 -- filtered by Sales
    ),     
    CALCULATE (
        [NumOfProducts],      -- Number of products
        ALL ( Sales )         -- filtered by ALL Sales
    )  
)

令人驚訝的是,這段代碼並沒有產生上面的報告。 相反,結果看起來像這樣:

在 PercOfProductsSold 列中,紅色產品的百分比是錯誤的。

3,ALL在CALCULATE函數中的作用

首先,瞭解將 ALL 用作過濾去除器與將 ALL 用作表函數之間的細微差別至關重要。 讓我們從頭開始:

ALL 是一個表函數,它返回一個表或一組列的所有行。 每當實際需要該結果時,這是 ALL 的正確行爲。 在非常特殊的 CALCULATE 過濾器情況下——並且僅在這種特殊情況下——ALL 不用於從表中檢索值。 相反,ALL 用於從過濾器上下文中刪除過濾器。 雖然函數名相同,但函數的語義完全不同。

當用作 CALCULATE 過濾器時,ALL 會刪除一個過濾器,它不返回表結果。
爲 ALL 的不同語義使用不同的名稱是個好主意。 一個非常合理的名稱應該是 REMOVEFILTER。
事實上,自 2019 年 10 月以來,Microsoft 在 Analysis Services 2019 和 Power BI 中引入了 REMOVEFILTERS 功能。REMOVEFILTERS 類似於 ALL,但它只能用作 CALCULATE 中的過濾器參數。 雖然 REMOVEFILTERS 可以替代 ALL,但不能替代用作 CALCULATE 修飾符的 ALLEXCEPT 和 ALLSELECTED。

通過檢查 PercOfSoldProducts 的分母,讓我們更好地理解它:

PercOfProductsSold =
DIVIDE (
    CALCULATE (
        [NumOfProducts],      -- Number of products 
        Sales                 -- filtered by Sales
    ),     
    CALCULATE (
        [NumOfProducts],      -- Number of products
        ALL ( Sales )         -- filtered by ALL Sales
    )  
)

在這種情況下,ALL 是 CALCULATE 的過濾器參數。 因此,它充當 REMOVEFILTERS,而不是 ALL。 當 CALCULATE 計算分母中的過濾器時,它會找到 ALL。 ALL 要求從擴展的銷售表中刪除任何過濾器,其中包括 Product[Color]。 因此,過濾器被刪除,但沒有結果返回給 CALCULATE。

因爲沒有返回結果,所以擴展的 Sales 表沒有被 CALCULATE 用作過濾器。 下面的代碼是等價的,這裏是使用 REMOVEFILTERS 函數而不是 ALL 的相同代碼:

PercOfProductsSold =
DIVIDE (
    CALCULATE (
        [NumOfProducts],          -- Number of products
        Sales                     -- filtered by Sales
    ),     
    CALCULATE (
        [NumOfProducts],          -- Number of products
        REMOVEFILTERS ( Sales )   -- with filters removed by Sales
    )  
)              

使用 ALL ( Sales ) 並不意味着“使用 Sales 中的所有行進行過濾”。 這意味着,“從銷售中刪除任何過濾器”。 通過對公式讀取方式的這一小改動,現在很明顯,如果不應用過濾器,產品數量就是產品總數。 因此,分母總是計算 2,517 而不是 1,170。 這解釋了爲什麼百分比從 4.36% 上升到 2.03%。

這種行爲肯定看起來很奇怪。 然而,正如 DAX 通常的情況一樣,這種行爲一點也不奇怪,就是這樣。 如果它不符合我們的期望——那麼問題是我們的知識有限,而不是行爲本身。

此時,看看如何正確編寫公式很有趣。 如圖所示,ALL 是不夠的,因爲它不返回其值,它只刪除過濾器。 一個選項是仍然使用 ALL,但將它移到外部 CALCULATETABLE 中。 通過這樣做,ALL 仍然表現得像 REMOVEFILTERS,但 CALCULATETABLE 強制返回結果:

PercOfProductsSold =
DIVIDE (
    CALCULATE (
        [NumOfProducts],
        Sales
    ),
    CALCULATE (
        [NumOfProducts],
        CALCULATETABLE ( ALL ( Sales ) )
    )
)

在 ALL 之外使用 CALCULATETABLE 看起來像個把戲,但事實並非如此。 它實際上改變了公式的語義,明確表示需要 ALL ( Sales ) 的結果才能過濾公式。 使用不太優雅的公式可以獲得類似的行爲:

PercOfProductsSold =
DIVIDE (
    CALCULATE (
        [NumOfProducts],
        Sales
    ),
    CALCULATE (
        [NumOfProducts],
        FILTER ( ALL ( Sales ), 1 = 1 )
    )
)

在這種情況下,是 FILTER 強制返回 ALL (Sales) 的結果,方法是使用具有始終計算爲 TRUE 的條件的虛擬過濾器。

值得注意的是,所有用作過濾器參數的表實際上都是擴展表。 因此,刪除過濾器的操作不僅會影響基表,還會影響整個擴展表。 ALL ( Sales ) 在 Sales 的擴展版本上充當 REMOVEFILTERS,從表和所有相關維度中刪除過濾器。

在 ALLEXCEPT 的情況下,此行爲尤爲重要。 考慮以下措施:

NoFilterOnProduct =
    CALCULATE (
        [Sales Amount],
        ALLEXCEPT ( Sales, Sales[ProductKey] )
    )

在此示例中,ALLEXCEPT 使用一列和三個表作爲參數。 可以使用包含在用作第一個參數的表的擴展版本中的任何表或列。

 

參考文檔:

Manageing ALL functions in DAX

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章