CALCULATE 庖丁解牛系列- CALCULATE專解(1)

CALCULATE之庖丁解牛系列 -- CALCULATE專解(1)

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ---- 學(xué)習(xí)DAX的門票

公眾號(hào):零售數(shù)據(jù)BI-laoliu? QQ: 2889374742

? ? 前言:

? ? ? 特別申明:本系列文檔為方便自己學(xué)習(xí)而整理(因?yàn)榉枪俜?,參考了一些網(wǎng)絡(luò)上官方發(fā)布的文檔知識(shí)內(nèi)容及簡(jiǎn)體筆記。在此一一致謝)。
? ? ? Power非官方DAX雖然分為多個(gè)系列,但實(shí)際是即關(guān)聯(lián)又獨(dú)立。大部分內(nèi)容并不是按順序進(jìn)行。這不是DAX的啟蒙文,但盡量從基礎(chǔ)部分開始。
? ? ? ? 這個(gè)CALCULATE系列其實(shí)醞釀了好幾次。因?yàn)槭荄AX最基礎(chǔ)的、最全面的部分,總覺得整理起來(lái)很難。也由于自己在該領(lǐng)域的非專業(yè)性、非科班性的局限……。
? ? ? ? 當(dāng)然,既然已經(jīng)開始,那便開始!CALCULATE系列可能會(huì)持續(xù)很久(初步設(shè)計(jì)為108式(對(duì)應(yīng)CALCUALTE的知識(shí)點(diǎn),可能會(huì)在不同的合適位置提出來(lái),但是可能會(huì)在其他業(yè)務(wù)場(chǎng)景中詳細(xì)說(shuō)明)。取108式,可能是因?yàn)檫@容易讓人關(guān)聯(lián)性想起梁山108條好漢。其他的系列都是這個(gè)系列的輔助并與之相關(guān))……。

? ? ? ? 注:所有Power非官方系列內(nèi)容,屬于“Power BI非官方”獨(dú)家發(fā)布,引用及轉(zhuǎn)載請(qǐng)注明出處或聯(lián)系本人。
? ? ?
這是一個(gè)浮躁的年代。我本來(lái)也想使用快餐式的一句話、一個(gè)圖、一個(gè)GIF的啟蒙類寫法。然而,經(jīng)過(guò)仔細(xì)的、漫長(zhǎng)的、艱苦的思考斟酌,還是不要為難自己為好……。讓我們開始:?

? ? 第1式:CALCULATE的隱式與顯式

? ? ? ? CALCULATE是DAX語(yǔ)言中最基本、最重要、最實(shí)用、最復(fù)雜、最難懂、最能代表DAX計(jì)算的函數(shù)。一句話,毫不夸張的說(shuō),CALCULATE代表了DAX的全部。? ? ?
? ? ? ? 類似的一個(gè)函數(shù)是CALCULATETABLE(它與CALCULATE的特性、行為幾乎相同,不同的是,CALCULATETABLE函數(shù):計(jì)算并返回一個(gè)或多個(gè)列表而不是標(biāo)量值),為了簡(jiǎn)單,僅以CALCULATE來(lái)分析。

? ? ? 本系列需要具備一定的DAX知識(shí)。因?yàn)镃ALCULATE的重要性涵蓋了DAX的所有概念,所以,知識(shí)點(diǎn)可能比較跳躍(比如直接引用某個(gè)DAX案例公式或者某個(gè)概念)。但我們盡量從最基礎(chǔ)的部分開始。
? ? ? 實(shí)際上,CALCULATE函數(shù)本身很簡(jiǎn)單,簡(jiǎn)單到可理解為一句話:定義一個(gè)DAX計(jì)算。

? ? ? 然而,實(shí)際上我們需要更全面的理解它,理解CALCULATE可能涉及的多個(gè)重要概念、規(guī)則、行為等。例如,它回答:CALCULATE在DAX是什么以及如何運(yùn)用的諸多問(wèn)題,我們略舉一些:

1、任何DAX都需要一個(gè)CALCULATE(隱式或顯式);
2、CALCULATE的計(jì)算執(zhí)行順序;
3、CALCULATE的行(列值)、列表篩選;
4、CALCULATE的第一個(gè)參數(shù)特點(diǎn);
5、CALCULATE的其他參數(shù)(第一個(gè)參數(shù)以外)特點(diǎn);
6、CALCULATE或CALCULATETABLE調(diào)整計(jì)算篩選;
7、CALCULATE 中ALL系列函數(shù)的行為;
8、CALCULATE中VALUES的作用;
9、CALCULATE的篩選轉(zhuǎn)換作用;
10、CALCULATE的列表關(guān)系的自動(dòng)傳遞作用;?
11、CALCULATE的篩選與擴(kuò)展表概念。
……
? ? ? 等一等,再列舉下去(我們說(shuō)有差不多108式?。?,估計(jì)要暈。在繼續(xù)之前,我們先要聊兩個(gè)似乎與本系列主題無(wú)關(guān),但又不得不闡明的觀點(diǎn)。
? ? ? ? 第一個(gè)觀點(diǎn),是學(xué)習(xí)DAX過(guò)程中需要記住的:很多時(shí)候,我們可以某種方式或某個(gè)自己能把握的概念來(lái)達(dá)到理解DAX的目的(官方也推出過(guò)很多通俗易懂的概念,本人也想搞個(gè)關(guān)于DAX的三部曲,哈哈)……。但DAX最終的內(nèi)部核心卻一直是一個(gè)專業(yè)的領(lǐng)域。
? ? ? ? 也就是說(shuō),你可以用這樣或那樣的方式、方法(思維)去理解DAX,但它內(nèi)部不一定是這樣!很多人學(xué)DAX,悟到一點(diǎn)東西,就上鋼上線,大喜過(guò)望,以為掌握了,可是、可是、可是……。真的是這樣嘛?只能很遺憾的告知你:不一定!
? ? ? ? 所以,列表+關(guān)系、擴(kuò)展表、列值、列表以及值列表、列表篩選等等,這些概念都是出于正確理解和使用DAX的需要……。用一句有點(diǎn)拗口的話來(lái)說(shuō):學(xué)習(xí)了DAX的這些概念,你不一定就“很DAX”,但“很DAX”的一定是先要理解了這些概念(使用DAX時(shí)不必要再糾結(jié)這些概念,所謂的“置于死地而后生”)。

? ? ? 第二個(gè)觀點(diǎn)?;诘谝粋€(gè)觀點(diǎn),讓我想起《天龍八部》的一句話:每當(dāng)研習(xí)一門絕世武功之前,必須有相應(yīng)的一種心法來(lái)容納它,否則容易走火入魔……。
? ? ? DAX學(xué)習(xí),目前似乎都有些亂: 先是“上下文”搞暈一大堆人;再是用反反復(fù)復(fù)的DAX把式,忽悠一大堆人;然后把人帶入 “學(xué)會(huì)幾句DAX口語(yǔ)”就能行走天下的誤區(qū),耽誤一大堆人;用超炫的幾個(gè)DAX場(chǎng)景圖表羨慕死一大批人……。一句話:易得DAX浮躁病。

? ? ? 其實(shí),所謂萬(wàn)變不離其中。首先,DAX是一門函數(shù)語(yǔ)言工具。必須先學(xué)習(xí)這門語(yǔ)言的基本字母、發(fā)音規(guī)律,之后才能掌握它。哪怕一開始慢一些,困難一些。你想想,你在那些”學(xué)幾句口語(yǔ)就走天下”的影響下,效仿炫酷得有些妖艷的場(chǎng)景引誘下所花的時(shí)間還少嗎?
? ? ? 準(zhǔn)官方SQLBI提到的2018版DAX學(xué)習(xí)之路,很多人拿來(lái)就用,發(fā)現(xiàn)水土不服……。陷入莫名的DAX知識(shí)旋渦里出來(lái)不了。學(xué)習(xí)完一個(gè)知識(shí)點(diǎn)、搞定一個(gè)公式、解決一個(gè)業(yè)務(wù)場(chǎng)景……。之后呢?總會(huì)遇到一個(gè)又一個(gè)問(wèn)題以及又回到瓶頸之處……。

? ? 有沒有想過(guò),所有這些,問(wèn)題出在哪里?

? ? ? 也有人總問(wèn)起一些接近這個(gè)問(wèn)題的問(wèn)題,一直都沒辦法回復(fù),怕自己水平有限,說(shuō)不清楚,如是總是說(shuō):這需要一個(gè)系列來(lái)回答。其實(shí),想想《天龍八部》里的一句話就明白了:無(wú)論使用何種方式學(xué)習(xí)某個(gè)絕世武功(DAX也應(yīng)該算),必須先要修煉出一個(gè)強(qiáng)大的內(nèi)功心法來(lái)容納它,否則注定會(huì)走火入魔!前面,我們將理解CALCULATE需要的知識(shí)點(diǎn)羅列了11項(xiàng)(當(dāng)然不止這些,我們計(jì)劃著108式)。基于CALCUALTE的了解,就是DAX的心法。

? ? 第2式:CALCULATE的元度量

當(dāng)你開始學(xué)習(xí)DAX時(shí),第一個(gè)真正的DAX公式不是:
[元度量_隱式]:= SUM(Sales[sale])
而應(yīng)該是包含? CALCULATE的DAX公式:
[元度量_顯式]:= CALCULATE(SUM(Sales[sale]))

? ? ? ? 也就是說(shuō):只有使用了CALCULATE才算是:定義了一個(gè)DAX計(jì)算。因?yàn)椋魏蜠AX都需要一個(gè)CALCULATE(隱式或顯式)。因此,第二個(gè)公式似乎更像DAX一些,前者不過(guò)是省略(隱式)了CALCULATE()而已。
? ? ? 我們把這種不帶任何篩選條件、CALCULATE只有第一參數(shù)的度量稱為元度量。
? ? ?
“任何DAX都需要一個(gè)CALCULATE(隱式或顯式)”,這是前面羅列的理解CALCULATE的第一個(gè)問(wèn)題,這也許是你一開始學(xué)習(xí)DAX,就需要面對(duì)的第一個(gè)DAX問(wèn)題。這需要我們厘清兩個(gè)公式不同的行為(有點(diǎn)繞口的部分):?
? ? (1)兩個(gè)公式對(duì)應(yīng)于CALCULATE的隱式與顯式,即前者公式隱式了CALCUALTE(),后者公式顯式使用CALCULATE()。
? ? (2)很顯然,接下來(lái)的問(wèn)題就是:為什么有隱式或顯式的CALCULATE的區(qū)別?即關(guān)于CALCULATE的第一個(gè)概念:隱式與顯式。
? ? ? 所謂隱式,就是內(nèi)部引擎能自動(dòng)完成,不需要定義的行為;
? ? ? 所謂顯式,就是必須由計(jì)算式(比如引用列表或函數(shù)定義,包括CALCULATE本身)定義的行為。
? ? ? 也就是說(shuō),兩個(gè)元度量公式能使用的前提,應(yīng)該是:

? ? ? ? (1)定義計(jì)算式;(2)加上引擎能自動(dòng)完成。即在兩個(gè)前提(顯式或隱式條件)下使用。例如,我們先在數(shù)據(jù)模型計(jì)算區(qū)域里定義一個(gè)元度量:

? ? ? 銷售:=SUM('訂單'[銷售額])

? ? ? 這時(shí)候,并沒有使用CALCULATE顯式定義它,但公式也能計(jì)算出正確的結(jié)果值(這里是針對(duì)度量所在表的計(jì)算),唯一的解釋(或條件)就是DAX內(nèi)部引擎能自動(dòng)判斷并執(zhí)行了該計(jì)算。如圖:

? ? ? 第3式:CALCULATE需要行、列表篩選共存

? ? (3)如果你已經(jīng)知道DAX的行、列篩選:任何一個(gè)DAX公式都需要同時(shí)具備行篩選和列表篩選(無(wú)論隱式還是顯式)。
? ? ? 注:應(yīng)該說(shuō),是每個(gè)DAX計(jì)算單元都需要行、列篩選(無(wú)論隱式還是顯式),一個(gè)較長(zhǎng)的DAX公式里可能包含一個(gè)或多個(gè)計(jì)算單元。

? ? ? 所以,這里對(duì)應(yīng)的就是隱式行篩選與顯式列篩選的定義及不同的行為區(qū)別。

? ? ? ? 注意:官方稱這兩種篩選為行上下文和篩選上下文。未做特別說(shuō)明,所有本人的DAX系列文章全部采用行篩選與列表篩選的稱呼。

? ? ? ? 接下來(lái)的問(wèn)題是:什么情況下是隱式還是顯式的篩選?

? ? ? 上圖中,銷售:=SUM('訂單'[銷售額]),這個(gè)被放置在模型表的度量能計(jì)算出正確的結(jié)果。那么,它就必須同時(shí)存在行、列表篩選。該公式告訴DAX,它針對(duì)數(shù)據(jù)模型里訂單表的[銷售額]這個(gè)列計(jì)算(對(duì)該列執(zhí)SUM()求和)。? ?
? ? ? ? 很顯然,DAX并不知道我們要計(jì)算的列表是哪一個(gè)、以及是針對(duì)該列的整列還是部分,這里的[銷售額]列是需要我們定義的計(jì)算列表(方式為SUM函數(shù)求和功能),因?yàn)镈AX可以被認(rèn)為是一種函數(shù)語(yǔ)言,因此,通俗點(diǎn)說(shuō):

? ? 你首先需要告訴DAX,計(jì)算的列表是什么?

? ? ? 上圖中,銷售:=SUM('訂單'[銷售額]):通過(guò)我們的定義,使它具有了顯式的列表篩選(先不討論列表關(guān)系傳遞、以及擴(kuò)展表概念等概念疊加,后面部分會(huì)討論這些)。
? ? ? 一旦定義了計(jì)算列表,而另一個(gè)看不見卻又存在的行篩選,即由引擎內(nèi)部自動(dòng)完成而無(wú)需再定義的隱式行篩選。這就是為什么明明只定義了一個(gè)顯式列表('訂單'[銷售額]列),并沒有指示它應(yīng)該按何種行方式計(jì)算,DAX卻能計(jì)算出正確的值的原因(后面將進(jìn)一步介紹這種“行的行為”)。

? ? ? 既然是自行完成,也就是說(shuō),不需要管行篩選是如何進(jìn)行的,你只要指定一個(gè)顯式列表給DAX,它就能正確計(jì)算!
? ? ? 例如,我們通常將該度量值放置在透視表里,因?yàn)檫@時(shí)它天然自帶行篩選,你只需要定義它為顯式列表即可。然后你改變透視表的行、列、切片器等,這其實(shí)是一組顯式列表篩選集,它們共同定義出計(jì)算列表(比如計(jì)算列表的范圍)。
? ? ? 這也就是我們通常所說(shuō)的:當(dāng)所有這些篩選器放入一個(gè)邏輯條件里(透視表或DAX定義)共同作用于顯式列表)時(shí),則形成當(dāng)前列表篩選—DAX計(jì)算所在計(jì)算列表環(huán)境(本概念后面章節(jié)中會(huì)更新它)。它改變:銷售:=SUM('tb訂單'[銷售額]) 定義的顯式列表篩選,隨之,與其對(duì)應(yīng)的隱式行篩選將不用定義、并由引擎自行完成行篩選。

? ? ? ? 注意:透視表的這種查詢篩選其實(shí)并不是真正的DAX查詢,而是MDX。這里從略,后面將有介紹。

? ? ? 第4式:CALCULATE定義顯式列表

? ? ? ? 而且,由于DAX內(nèi)部引擎是一個(gè)列式數(shù)據(jù)庫(kù),引擎始終認(rèn)為列表是可見的、存在的。換句話說(shuō),它始終執(zhí)行顯式列表。
? ? ? ? 因此,很多時(shí)候?yàn)榱俗孌AX能正確計(jì)算,需要將某些行行為作列表顯式化處理,以便內(nèi)部引擎能識(shí)別出來(lái)。而唯一有這種能力的只有CALCULATE與CALCULATETABLE函數(shù)。這一點(diǎn)是前面提到的第9點(diǎn)。所以,我們有了關(guān)于第一個(gè)元度量的注釋:

? ? ? ? 銷售:=SUM('訂單'[銷售額]) –-包含顯式列表篩選與隱式行篩選。

? ? ? 推而廣之,任何一個(gè)隱式(不帶)CALCULATE的元度量(比如由SUM、COUNT、MIN等函數(shù)直接定義的某個(gè)列表的計(jì)算),都包含一個(gè)顯式的列表篩選以及一個(gè)隱式的行篩選。也就是說(shuō),任何元度量(未加任何篩選條件的)都具有隱式的行篩選。

? ? ? 還是看看這些行為的運(yùn)用場(chǎng)景:

? ? (1)前面的公式:銷售:=SUM('訂單'[銷售額]) 。它針對(duì)數(shù)據(jù)模型計(jì)算(即針對(duì)整個(gè)表:這里是對(duì)應(yīng)的[銷售額]整列),因此,結(jié)果為整列的聚合值:=1758423,如圖:

? ? (2)因?yàn)橐孀詣?dòng)執(zhí)行行篩選,所以,只要改變顯式列表(比如不是整列—列表的部分或其他篩選定義)。剛才的公式計(jì)算針對(duì)的是整個(gè)數(shù)據(jù)模型表的計(jì)算,現(xiàn)在,我們?cè)跀?shù)據(jù)模型里改變它,比如針對(duì)時(shí)期列篩選出一段時(shí)期(這同時(shí)會(huì)篩選到[銷售額]列),結(jié)果將隨著改變:=62686(不是1758423)。

? ? ? 同一個(gè)公式,計(jì)算結(jié)果發(fā)生改變的原因只能是:顯式列表的改變(列表范圍的改變),因?yàn)檫@時(shí)候的行的行為是相同的(隱式行篩選行為是相同的—逐行掃描,即遍歷,這也是暫時(shí)的理解)。

? ? (3)再看看針對(duì)計(jì)算列的CALCULATE隱式與顯式:

? ? ? 我們新建一個(gè)[銷售列]的列。定義相同的公式:= SUM('訂單'[銷售額]) ,即針對(duì)[銷售額]計(jì)算。

? ? ? 結(jié)果并不是我們期待的,而是一個(gè)每行結(jié)果相同的值。這其中一定是與前面的度量行為發(fā)生了不一樣的變化。這里要分清:行、列篩選中,哪個(gè)是定義的,哪個(gè)是不需要定義的,或者再啰嗦點(diǎn)說(shuō),這有幾種可能:
? ? ? 1)不需要定義的、引擎能自動(dòng)執(zhí)行的隱式行篩選,被顯式定義了;
? ? ? 2)需要定義的顯式列表篩選,被隱式了;
? ? ? 3)或者隱式、顯式的行為完全都被顛倒了(該隱式的顯式了,該顯式的隱式了);
? ? ? 4)要不缺少列表篩選,要不缺少行篩選,或者兩者都沒有(很少見)。
? ? 在今后的DAX公式運(yùn)用中,經(jīng)常會(huì)出現(xiàn)這幾種情況,這里暫時(shí)略過(guò)。

? ? ? 要說(shuō)清這個(gè)問(wèn)題有點(diǎn)超前(涉及行列篩選概念),先做個(gè)預(yù)熱了解。下一個(gè)部分會(huì)詳說(shuō)。

? ? ? 本例中,涉及到計(jì)算列。因?yàn)槿魏斡?jì)算列都具有物理列表屬性(其實(shí)際就是一個(gè)物理表,需要占有內(nèi)存來(lái)存儲(chǔ)),請(qǐng)記住,在數(shù)據(jù)模型里,任何一個(gè)列本身并不具有單個(gè)行值(數(shù)據(jù)列表不具有行的概念,所以,你可以理解為:DAX里所有關(guān)于行的行為都是隱式的)。
? ? ? 當(dāng)然,列表的每一行都可以有一個(gè)不同的值。因此,如果想要定義單個(gè)列值,則需要定義出要使用的行。而指定要使用的行的唯一方法就是行篩選(下一部分將介紹的值列表篩選)。
? ? ? 我們其實(shí)已經(jīng)知道結(jié)果,對(duì)于計(jì)算為同一個(gè)值的這種行為,有DAX基礎(chǔ)的應(yīng)該都知道,這大都是因?yàn)槿鄙傩泻Y選的原因!本例中計(jì)算列的計(jì)算,并沒有行篩選,因而公式是錯(cuò)誤的,DAX拒絕計(jì)算。

? ? ? 問(wèn)題是,我們不是定義了:= SUM('訂單'[銷售額]),告訴DAX要聚合計(jì)算'[銷售額]列的值嗎?,而且,我們前面剛剛說(shuō)過(guò):計(jì)算中使用的SUM和MAX等聚合函數(shù)定義的公式:具有顯式的列表篩選,以及隱式的行篩選(即忽略行篩選)。
? ? ? 雖然我們用一句話:“計(jì)算列里缺少行篩選”就解釋清楚了,但研究這種行為很有用。后面還會(huì)繼續(xù)。

? ? ? 也就是說(shuō),我們真的是使用了迭代器以編程方式創(chuàng)建了行篩選,與前面的度量行為相同,這里的計(jì)算列都使用了同一DAX表達(dá)式,那么,區(qū)別應(yīng)該在于計(jì)算的內(nèi)容!前面已提問(wèn):
? ? ? 你首先需要告訴DAX計(jì)算的列表是什么?
? ? ? ?
問(wèn)題是,僅僅告訴DAX計(jì)算的列表是什么還不夠,還需要DAX引擎能夠聽得懂你的語(yǔ)言,并執(zhí)行你的定義。所以我們還得加上一句提問(wèn):
? ? ? ? 其次, DAX能識(shí)別和執(zhí)行你定義的列表計(jì)算嗎?

? ? ? 我們已經(jīng)明白,度量是在透視表或DAX查詢的當(dāng)前行、列(都是列表篩選)子集中計(jì)算的,而計(jì)算列是在它所屬的表的行級(jí)別上計(jì)算的。
? ? ? 所以,當(dāng)你使用SUM('訂單'[銷售額]) 時(shí),你定義的是所有這些條件下行的總和。本例中的DAX計(jì)算列,只有列表篩選,因此只能使用列表篩選來(lái)確定列值(整列的列值):

? ? ? 一方面,雖然計(jì)算列不存在行篩選,但還是可以通過(guò)行的行為來(lái)了解該問(wèn)題。? ?
? ? ? 我們假設(shè)它存在行篩選,則它為第一行創(chuàng)建一個(gè)行篩選,然后調(diào)用公式計(jì)算,一直到遍歷整個(gè)表的所有行。公式計(jì)算了當(dāng)前篩選中的所有銷售額的總和。所以,現(xiàn)在真正的問(wèn)題是:當(dāng)前的篩選是什么?? ? ? ? 你當(dāng)然可能會(huì)回答:計(jì)算所在的數(shù)據(jù)模型表呀。但是,因?yàn)檫@里并沒有當(dāng)前的活動(dòng)篩選存在,DAX引擎會(huì)將該計(jì)算列作為定義的一部分(即針對(duì)定義的顯式列表:[銷售額]列)計(jì)算。

? ? ? 另一方面,即使有行篩選,SUM也會(huì)忽略它。它能使用的只有列表篩選(同一個(gè)不變的顯式列表篩選),而當(dāng)前篩選現(xiàn)在是完整的數(shù)據(jù)模型表(計(jì)算列所在的表,這意味著每次行篩選對(duì)應(yīng)的都將是同一個(gè)顯式列表)。因此,你會(huì)得到一個(gè)相同的銷售總額(所有行的總值)。結(jié)果如前面的圖所示。

你可以理解為,這時(shí)的行篩選與列表篩選是同一個(gè)篩選(都對(duì)應(yīng)于整刻)。

? ? ? 現(xiàn)在,我們換一種方式理解。根據(jù)隱式、顯式篩選的定義來(lái)理解:定義一個(gè)計(jì)算列,對(duì)于DAX引擎來(lái)說(shuō)該計(jì)算列屬于顯式列表。而事實(shí)上,計(jì)算列是不需要定義的,DAX引擎自然知道你針對(duì)的總是該列(沒有度量方式的顯式列表變化)并能執(zhí)行計(jì)算。
? ? ? 也就是說(shuō),主觀上,我們似乎想給DAX定義顯式的列表篩選(事實(shí)也確實(shí)如此:這是你寫SUM('訂單'[銷售額]) 這個(gè)計(jì)算列的初衷),但客觀上,相對(duì)于DAX引擎來(lái)說(shuō),這時(shí)候其實(shí)是隱式的列表篩選(無(wú)須顯式定義)。
? ? ? 使用SUM(),則是為了添加計(jì)算需要的隱式行篩選,以便運(yùn)用DAX引擎的隱式行篩選,計(jì)算出每一行的正確值。
? ? ? 可是,這時(shí)候無(wú)論這個(gè)隱式的行篩選是否存在,實(shí)際上,它面對(duì)的都是一個(gè)隱式的列表篩選,似乎行、列篩選都是隱式的行為(這種引擎的行為,相當(dāng)于完全需要引擎自動(dòng)執(zhí)行計(jì)算而變得毫無(wú)意義,這種行為與我們后面要說(shuō)的ALL的絕對(duì)值結(jié)果行為還不一樣),這就給我們一個(gè)提示或者說(shuō)是結(jié)論:

? ? ? ? 通常,DAX計(jì)算(含計(jì)算單元)需要的都是一個(gè)顯式的列表篩選以及一個(gè)隱式的行篩選。

? ? 第5式:CALCULATE顯式列表總伴隨隱式行篩選

? ? (4)通過(guò)前面的介紹,我們來(lái)看看正確的計(jì)算列公式與度量公式的幾種行為方式以及區(qū)別(關(guān)于計(jì)算列與度量的詳細(xì)區(qū)別容后再續(xù)):

? ? ? 1)我們可以直接定義一個(gè)顯式列表的計(jì)算列,這種行為相當(dāng)于顯式列表后,伴隨而來(lái)的是該列表篩選同等效果的隱式行篩選。更好的、可能有些拗口的理解是:你可以認(rèn)為這是:一個(gè)顯式列表伴隨對(duì)應(yīng)的一個(gè)隱式行篩選。
? ? ? 是的,你沒有看錯(cuò),無(wú)論列表還是行篩選都只有一個(gè)!雖然我們還沒有具體了解DAX引擎內(nèi)部是如何運(yùn)行的,但肯定不是前面討論的行行為:一行一行的遍歷!如果這樣,那DAX的效率實(shí)在是太低了!也沒有任何優(yōu)勢(shì)與存在的必要了。
? ? ? 這時(shí)候,你只要知道遍歷只發(fā)生一次就行?;蛘哂涀。河?jì)算列里只要顯式定義列表后,就不必考慮隱式行篩選(前面的研究只是為了更好的理解),這是DAX中難于理解的一個(gè)行為。如圖,直接定義 =[銷售額],結(jié)果相當(dāng)于復(fù)制了某個(gè)列表。

? ? ? ? 2)接著,只要是針對(duì)某個(gè)表格的計(jì)算列操作,該表格里所有的列表都可以被定義為顯式列表參與計(jì)算。比如,我們可以直接定義兩個(gè)或多個(gè)標(biāo)量值列表之間的計(jì)算。如下圖的兩個(gè)時(shí)期列表的差異計(jì)算(相減)。

? ? ? 3)如前所說(shuō),上圖中的公式運(yùn)用在度量中,則會(huì)得到一個(gè)“錯(cuò)誤號(hào)”提示。原因當(dāng)然是已經(jīng)提示的那樣:缺少隱式的行篩選。

? ? ? 4)既然是缺少隱式的行篩選,我們使用聚合函數(shù)的行行為特性,分別對(duì)兩個(gè)列加上聚合計(jì)算(所有迭代函數(shù)都具有隱式行篩選行為,這將針對(duì)兩列都創(chuàng)建了各自的行篩選)。如圖:結(jié)果正確。

? ? ? 5)在公式 = SUM('訂單'[銷售額]), 前面加上CALCULATE(顯式定義列表篩選):
= CALCULATE ( SUM('訂單'[銷售額])),這時(shí)候,只要顯式定義了列表篩選,那么,引擎會(huì)自動(dòng)創(chuàng)建該顯式列表篩選對(duì)應(yīng)的隱式行篩選(這是CALCULATE的行為之一,前面已羅列,后面會(huì)論述)。如圖所示,計(jì)算列的公式能計(jì)算出正確的值。

因此,也就有了CALCUALTE的第6式:

? ? 第6式:CALCULATE將隱式行篩選顯式為列表

? ? ? CALCULATE第6式,就是前面提到的CALCULATE的一個(gè)很重要的行為:它將隱式行篩選轉(zhuǎn)變?yōu)椋ǘx為)與之等效的顯式列表篩選。這一點(diǎn)與前面的第5式是相通的,將隱式行篩選轉(zhuǎn)變?yōu)椋ǘx為)與之等效的顯式列表篩選后,并不是行篩選消失了或不需要了,而是可能同時(shí)具備了隱式的行篩選或與其他行篩選組合成新的當(dāng)前計(jì)算篩選,這也是使用CALCUALTE這樣做的目的。
? ? (5)今后在學(xué)習(xí)DAX的過(guò)程中,將不可避免的接觸到顯式與隱式以及對(duì)應(yīng)的篩選問(wèn)題。而且由于所在的計(jì)算列表集的不同、以及所定義的邏輯條件不同而更加復(fù)雜。

? ? ? 我們提前舉例一個(gè)顯式列表篩選的情況:我們知道,LASTNONBLANK函數(shù)是一個(gè)迭代函數(shù)(遍歷所有行值),所以,與所有迭代器一樣, 它有一個(gè)行篩選, 但可能沒有列表篩選。

因此,以下公式將計(jì)算錯(cuò)誤:

最近余額: =
CALCULATE (SUM ( 數(shù)據(jù)表[銷售額] ) ,
LASTNONBLANK ( 日歷表[時(shí)期] ,
SUM ( 數(shù)據(jù)表[銷售額] ) ) )? -- 隱式行篩選,沒有顯式列表篩選。

正確的公式,應(yīng)該使用顯式的CALCULATE():

最近余額: =
CALCULATE (SUM ( 數(shù)據(jù)表[余額] ),
LASTNONBLANK ( 日歷表[時(shí)期],
CALCULATE ( SUM ( 數(shù)據(jù)表[余額] ) ) )) --隱式行篩選,被轉(zhuǎn)換為顯式列表

? ? 用圖標(biāo)示出隱式與顯式的關(guān)系:

或者標(biāo)示為如下圖:

? ? ? 到現(xiàn)在為止,我們都在圍繞著一個(gè)主題在討論,那就是DAX兩種形態(tài)的元度量,并由此展開的有關(guān)CALCULATE的行為方式。這些行為方式的理解,是今后熟悉更復(fù)雜、邏輯條件更多的DAX的基礎(chǔ)。我們把這兩個(gè)元度量再次羅列出來(lái):

[元度量_隱式]:= SUM(Sales[sale])
[元度量_顯式]:= CALCULATE(SUM(Sales[sale]))

? ? ? 通過(guò)前面的啰嗦,第二個(gè)度量公式:CALCULATE(SUM(Sales[sale])你應(yīng)該不會(huì)像一開始那樣覺得它很奇怪,至少稍微理解了一點(diǎn)。當(dāng)然,我們接下來(lái)要講到CALCULATE的參數(shù)語(yǔ)法、規(guī)則、行為方式等。

未完待續(xù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容