我們之前已經(jīng)學(xué)過,calculate還有另外一個重要的功能,就是它會把當(dāng)前的行上下文轉(zhuǎn)換為篩選上下文。
要介紹這個特性,我們要使用calculate建立一個計算列。計算列會自動生成行上下文,所以,會產(chǎn)生一個上下文的轉(zhuǎn)換。舉例說明,我們在product表中定義了一個計算列,使用下面的DAX表達(dá)式:
Product[SumOfUnitPrice] = SUM ( Product[Unit Price] )
這個函數(shù)對所有產(chǎn)品到產(chǎn)品求和。表達(dá)式在有一個行上下文,但是沒有篩選上下文。所以他會返回表中所有產(chǎn)品都unit price總和,而不是當(dāng)前行產(chǎn)品的金額。結(jié)果如下圖所示:

現(xiàn)在,我們建立另外一個度量值,稍微修改一下之前的代碼。這次使用calculate
Product[SumOfUnitPriceCalc] = CALCULATE ( SUM ( Product[Unit
Price] ) )
什么?這次calculate里面只有一個表達(dá)式?篩選條件的參數(shù)呢?實際上,這里我們使用的是calculate的最簡單的模式。我們之前說過,這個函數(shù)中,只有第一個也就是計算表達(dá)式是必須的,所以這樣只有一個參數(shù)的寫法是完全符合規(guī)范的。這時候,calculate不會改變?nèi)魏我延械暮Y選上下文,但是,函數(shù)其他的功能還是繼續(xù)有效:它會把當(dāng)前的行上下文,自動轉(zhuǎn)換為篩選上下文。注意,所有的當(dāng)前的行上下文都會被合并為新的篩選上下文,我們后面會詳細(xì)的介紹。
這個案例里面,calculate會尋找存在的行上下文,然后找到一個product,這是因為現(xiàn)在是在計算列當(dāng)中,calculate把當(dāng)前行轉(zhuǎn)換為等效的篩選上下文。
calculate把當(dāng)前產(chǎn)品的行轉(zhuǎn)化為篩選上下文,然后計算sum(product[unit price]).計算的結(jié)果是當(dāng)前產(chǎn)品的結(jié)果。

第一次看到這個計算邏輯,可能會難以理解為什么calculate會上下文轉(zhuǎn)換。不過等你開始使用了這個特性,你會喜歡上這個函數(shù)賦予你的強(qiáng)大的能力。
另外,上下文轉(zhuǎn)換還有另外一個非常重要的地方。我們知道行上下文和篩選上下文在關(guān)系中的行為是不相同的。行上下文不會通過關(guān)系自動傳遞,而篩選上下文會自動傳遞。因此,當(dāng)上下文轉(zhuǎn)換的時候,篩選上下文就會自動傳遞到其他的相關(guān)表。
另外,我們用另外一種方法可以幫助我們理解這個行為。還是在product表中,我們建立兩個度量值。
Product[SalesAmount] = SUM ( Sales[SalesAmount] )
Product[SalesAmountCalc] = CALCULATE ( SUM (Sales[SalesAmount] ) )
下圖中,我們可以看到結(jié)果,兩個顯然不同。

如我所見,salesamount列包含了所有的產(chǎn)品的銷售額,而salesamountcalc則是只有當(dāng)前產(chǎn)品的銷售額。calculate把當(dāng)前行的產(chǎn)品信息傳遞到了sales表,然后計算結(jié)果,所以最后顯示的就是當(dāng)前產(chǎn)品的銷售額
注意,當(dāng)calculate執(zhí)行的時候,上下文轉(zhuǎn)換會發(fā)生在所有的上下文環(huán)境中。事實上,我們可能會有多個上下文在多個表。例如,如果你在product表中,對計算列使用averagex迭代customers,那么上下文轉(zhuǎn)換會發(fā)生在product和customer表中,sales表會同時收到兩個篩選器??聪旅孢@個函數(shù):
Product[SalesWithSUMX] =
AVERAGEX (
Customer,
CALCULATE ( SUM ( Sales[SalesAmount] ) )
)
這函數(shù)計算了買這個產(chǎn)品的所有客戶的平均額。calculate中的sum函數(shù)在篩選上下文中計算,計算當(dāng)前產(chǎn)品(由計算列產(chǎn)生),當(dāng)前人(由averagex產(chǎn)生)的銷售額。這里有個簡單的方法來記憶:在calculate中沒有行上下文,只有篩選上下文。