? ? 第27式? CALCULATE的DAX函數(shù)與Excel函數(shù)比較
? ? ? 參考閱讀:《DAX圣經(jīng)第一章、第二章、第四章》。
? ? ? 為了內(nèi)容的連貫,本部分(CALCULATE系列(7),主要內(nèi)容來自DAX圣經(jīng)的這幾章的簡體修改。
? ? ? 只所以將基礎(chǔ)的一些內(nèi)容放在了較為后面的式后,是因為之間的內(nèi)容銜接。
? ? ? 為了鞏固你對列表引用以及定義值列表有一個全面的認識,我們還將啰嗦一些知識點,來作為后面內(nèi)容的過渡。
? ? ? 你可能已經(jīng)知道Excel公式語言了,DAX與它有點像。畢竟,DAX的根是在Excel的Powerpivot中,后者也試圖將這兩種語言保持相似,以使得向新語言的過渡更加容易。然而,它們之間存在一些非常重要的區(qū)別。
? ? ? ? 1、單元格與列表
? ? ? 在Excel中,你可以對單元格使用其坐標(biāo)進行引用。因此,你寫公式如下:
? ? ? ? = (A1 *1,25) - B2
? ? ? 通過前面的介紹,你知道DAX函數(shù)是不同的。在DAX中,沒有單元格(行)的概念以及不存在單元格。DAX在表和列上工作,而不是在單元格上。
? ? ? 所以,當(dāng)需要寫DAX表達式時,你只能指向表和列。表和列的概念在Excel中并不新鮮。實際上,如果將Excel范圍定義格式為表(通過使用表格函數(shù)處理的格式。比如Ctel+L將單元格區(qū)域轉(zhuǎn)化為列表格式??梢栽贓xcel中編寫引用表和列的表達式。如果你看圖1 - 5,你會發(fā)現(xiàn)列SalesAmount計算在同一個表中引用列的表達式,而不是工作簿中的單元格。

? ? ? 圖中? 可以在Excel表中使用列名。
? ? ? 要在Excel中引用列,可以使用[@ ColumnName]格式引用表中的某個列,其中ColumnName是要引用的列的名稱,@ 符號表示“取當(dāng)前行的值”。
? ? ? 盡管這樣的語法不是很直觀,通常你不會寫這些表達式。它們只是簡單地單擊一個單元格,Excel自動計算出正確的結(jié)果。你知道Excel有兩種不同的計算方法:即還可以使用標(biāo)準(zhǔn)的單元格引用(在這種情況下,單元F4的公式應(yīng)該是E4 * D4),或者可以使用列引用:
? ? Sales[SalesAmount] =Sales[ProductPrice] * Sales[ProductQuantity]
? ? ? 在Excel里使用列引用的優(yōu)點是,列的所有單元格使用的是相同的表達式,Excel運用該公式計算每一行的不同值。DAX在表格模型里工作,所以所有公式都需要引用列。比如,在DAX公式中,之前的乘法運算是這樣的:
? ? ? 1) Excel:IF([@ SalesAmount]>10,1,0)
? ? ? ? 2)DAX : IF(Sales[SalesAmount]>10,1,0)
? ? ? ? Excel和DAX的語法不同的一個重要方面是對整個列的引用。可能已經(jīng)注意到,在寫入[@ productquantity]時,@ 表示“當(dāng)前行的值”。當(dāng)使用DAX時,你不需要指定這個。
? ? ? DAX語言的默認行為是獲取”當(dāng)前行”的值。我們可以回憶一下前面第一部分中提到的概念:這種DAX內(nèi)部引擎自動完成的行為,我們稱之為“隱式行行為”。
? ? ? 通過學(xué)習(xí),我們已經(jīng)可以解釋:在前面的公式 2)中,Sales[SalesAmount]>10是一個值列表(具有隱式行行為:自動獲取“當(dāng)前行”),同時它又是IF引用的“列表”(使用整個值列表的值,所以是以列表形態(tài)被引用)。
? ? ? 如果在Excel中,想要引用整個列(即該列中的所有行,那么,你可以刪除@符號,如圖1 - 6所示。圖1-6 Excel列表式數(shù)據(jù)區(qū)域中,可以省略列名前面的@符號來引用整個列。

? ? ? [AllSales]的值在所有行中是相同的,因為它計算的是[SalesAmount]列的總數(shù)。換句話說,在當(dāng)前行的列值與整個列的值之間存在一個句法差異。
? ? ? DAX公式是不同的。在DAX公式中,你可以這樣寫圖1 - 6的AllSales表達式:
? ? ? [AllSales] :=SUM( Sales[SalesAmount] )
? ? ? ? 使用列來獲?。ǘx)特定行的值和使用(引用)列作為一個整體這兩種語義,語法上其實并沒有區(qū)別。DAX知道這是對該列的所有值求和,因為在聚合函數(shù)(SUM)中使用了列名(在這個例子中是SUM(Sales[SalesAmount]),這符合:聚合函數(shù)需要一個列名稱作為參數(shù)傳遞。因此,盡管Excel檢索數(shù)據(jù)時需要顯式的語法來區(qū)分這兩種類型的數(shù)據(jù),但DAX會自動地執(zhí)行歧義消除。至少在開始的時候,這可能會讓人感到困惑。
? ? ? ? 從這點上看,Excel和DAX是兩種不同的函數(shù)式語言。
? ? ? 這兩種語言非常相似的一個方面是:Excel和DAX都是函數(shù)式語言。函數(shù)式語言是由基本函數(shù)調(diào)用的表達式構(gòu)成的。無論是在Excel中還是在DAX中,都沒有語句、循環(huán)和跳轉(zhuǎn)的概念,但這在許多編程語言中都是常見的。
? ? ? 在DAX公式中,一切都只是一種函數(shù)表達式。
? ? ? 對于來自不同語言的程序員來說,這一方面通常是一個挑戰(zhàn),但是對于Excel的用戶來說,這一點并不奇怪。
? ? 2、使用迭代器(多個篩選)
? ? ? 第一個DAX的概念就是迭代器。Excel工作時,習(xí)慣于一次執(zhí)行一個步驟。在前面的例子中,已經(jīng)看到,為了計算銷售總額,需要創(chuàng)建一個列,其中包含價格乘以數(shù)量,然后,作為第二步,引用它來計算總銷售額(當(dāng)前的總值,總是一個值)。這個數(shù)值將是有用的,例如,作為計算每個產(chǎn)品銷售占比百分比的分母。
? ? ? 使用DAX,可以使用迭代器在單個步驟中執(zhí)行相同的操作。迭代器按照公式指定步驟進行相同的計算。例如:你可能很熟悉的一句DAX計算過程的規(guī)則:
? ? ? 它遍歷表,并在表的每一行執(zhí)行一次計算,聚合結(jié)果以生成所需的單個值,并填充在對應(yīng)的每一行。在前面的示例中,可以使用SUMX迭代器的方法來計算所有銷售的和:
? ? ? [AllSales] := SUMX(Sales, Sales[ProductQuantity] *Sales[ProductPrice])
? ? ? 該公式是我們已經(jīng)很熟悉了的X后綴系列迭代器函數(shù)的套路:引用一個表(這里是Sales表),然后遍歷(行行為)該表的所有行,第二個參數(shù)定義的值列表在該表內(nèi)計值。
? ? ? 我們說,這種方法有優(yōu)點也有缺點。
? ? ? 一方面,優(yōu)點是:可以執(zhí)行許多復(fù)雜的列表計算,而不必為了只對某些特定的公式有用時,添加不必要的--占用內(nèi)存的計算列。
? ? ? 另一方面,缺點是:使用DAX進行編程的視覺效果比不上Excel。事實上,你看不到價格乘以數(shù)量的列計算:它只存在于計算的生命周期中。
? ? ? 當(dāng)然,你仍然可以選擇創(chuàng)建一個新的計算列,來計算[price ]和 [quantity](即價格和數(shù)量)的乘積。然而,正如稍后將學(xué)到的,這很少是一個好的實踐,因為它使用了寶貴的內(nèi)存,可能會減慢計算速度。
? ? ? 我們需要明確一點:這不是編程語言之間的區(qū)別,而是一種思維模式的區(qū)別。就像這個星球上的任何人類一樣:當(dāng)使用Excel的時候,可能都習(xí)慣于在web上搜索試圖解決的場景,例如復(fù)雜公式或解決方案模式。而且,很有可能你都會找到一個幾乎可以實現(xiàn)你需要的公式。你可以復(fù)制這個公式、定制它、使用它來滿足你的需要,而不必過于擔(dān)心它是如何工作的。
? ? ? 這種方法在Excel中有效,但卻與DAX沒有關(guān)系。對于DAX,你將需要學(xué)習(xí)一些新的DAX工作理論,并徹底了解當(dāng)前計算列表是如何工作的,然后才能寫出好的DAX代碼。如果沒有適當(dāng)?shù)睦碚摶A(chǔ),DAX將會計算出莫名奇怪的字符、或者莫名其妙的數(shù)字。出現(xiàn)這種現(xiàn)象,問題不在DAX,而是你還不清楚它是怎樣工作的。
? ? ? 幸運的是,DAX的理論僅限于幾個重要的概念,這在我們所有CALCULATE系列中將得到解釋,而最最關(guān)鍵的是DAX的列表概念,例如如何引用列表與定義值列表等。
? ? ? 一旦你掌握了它的內(nèi)容,DAX對你就沒有任何秘密了,學(xué)習(xí)它,后面的實際運用反而顯得相對容易一些,不過是一個獲得經(jīng)驗的過程問題。然而,試圖更進一步熟悉它將更困難,除非你對DAX的理論基礎(chǔ)建立得非常好。記住,了解只是成功的一半。
? ? ? 所以,了解DAX(CALCULATE)我們需要108式的差不多一半的式。
? ? ? 很多人一開始學(xué)習(xí)DAX,就想像學(xué)習(xí)Excel那樣:照搬幾個公式,以為理解了,其實不然,這里真正掌握DAX還有很長的一段路......。
? ? ? 前面提到DAX語言與其他語言的區(qū)別,這里簡單介紹一下很有必要。
? ? 第28式? CALCULATE的DAX語言與其他語言的比較
? ? 1、DAX針對SQL
? ? ? 如果習(xí)慣于SQL語言,那么,可能已經(jīng)與許許多多、各種各樣的表打過交道,并總是會在表的某些列之間定義關(guān)系以創(chuàng)建連接。這與在DAX是相同的。因為,在DAX公式中,計算的實際是一種查詢一組由關(guān)系連接的表的聚合計算問題。從這點上看,SQL工作者會很熟悉,就像是回到自己的家一樣。
? ? ? ? 但是,這兩者之間有很大的區(qū)別:
? ? ? 1)SQL和DAX之間的第一個區(qū)別是模型中關(guān)系的工作方式。在SQL中,可以在表之間設(shè)置外鍵來聲明關(guān)系,但是引擎在查詢中并不使用這些外鍵,除非你聲明它們。例如,如果有一個Customer表和一個Sales表,其中的[CustomerKey]是Customer--客戶表的主鍵以及銷售表的外鍵,那么,你可以編寫如下的查詢:
SELECT
Customers,CustomerName,
SUM( Sales,SalesAmount ) AS SumOfSales
FROM
Sales
INNER JOIN Customers
ON Sales,CustomerKey = Customers,CustomerKey GROUPBY
Customers,CustomerName
? ? ? 即使使用外鍵聲明了模型表中的關(guān)系,你仍然需要顯式并聲明查詢中的聯(lián)接條件。盡管這樣會使查詢變得更加冗長,但這是必須的,因為它允許在不同的查詢中使用不同的連接條件,以便在查詢的表達性方面給予最大的自由。
? ? ? 但是,在DAX公式中,關(guān)系是模型固有的一部分,它們都可以被視為一種左外聯(lián)結(jié)。一旦在模型中創(chuàng)建了關(guān)系,當(dāng)使用與主表相關(guān)的列時,不再需要在查詢中指定連接類型:DAX會在查詢中自動進行左外連接。因此,可以將以上的SQL查詢用DAX代替如下:
EVALUATE
SUMMARIZE(Sales,
Customers[CustomerName],"SumOfSales",SUM(Sales[SalesAmount] )
? ? ? 上述DAX公式中,因為關(guān)系是模型的一部分,會始終自動跟隨模型(只要你不刪除已有的關(guān)系),DAX能識別Sales和Customer表之間存在的關(guān)系。這里,SUMMARIZE函數(shù)只是引用Customers表的[CustomerName]列來自動計算,這個過程里,并沒有任何關(guān)鍵字被SUMMARIZE聲明。DAX中不需要聲明模型表中的關(guān)系的特點很重要,這在后面的DAX的列表關(guān)系在DAX公式中的運用中將會詳說。
? ? ? 2)DAX是函數(shù)性語言
? ? ? ? 既然SQL是一種聲明性語言。
? ? ? ? 一方面,它通過使用SELECT語句聲明要檢索的數(shù)據(jù)集,靈活地查詢所需的數(shù)據(jù),而不必擔(dān)心引擎如何檢索信息。
? ? ? 另一方面,由于DAX是一種函數(shù)性語言。在DAX公式中,每一個表達式其實都是一個函數(shù)的調(diào)用過程,如果一個函數(shù)參數(shù)又依次為引用其他函數(shù)調(diào)用,那么,參數(shù)的動態(tài)調(diào)用(迭代)可能會導(dǎo)致非常復(fù)雜的查詢過程,為了計算出結(jié)果,DAX會執(zhí)行這些過程。
? ? ? 例如,如果只想檢索居住在Europe歐洲的客戶,你可以用SQL編寫這個:
SELECT
Customers,CustomerName,SUM( Sales,SalesAmount ) ASSumOfSales
FROM
Sales
INNER JOIN Customer ON Sales,CustomerKey = Customers,CustomerKey
WHERE
Customers,Continent ='Europe'GROUPBY
Customers,CustomerName
? ? ? 如果使用DAX,在查詢中不必聲明WHERE條件。相反,使用一個特定的函數(shù)(FILTER)來篩選結(jié)果:
EVALUATE
SUMMARIZE(
FILTER(Customers,Customers[Continent] ="Europe"),Customers[CustomerName],"SumOfSales",SUM( Sales[SalesAmount] ))
? ? ? 這里的FILTER(篩選器)是一個函數(shù):它遍歷整個Customers,只返回Continent--居住地僅僅為Europe--歐洲的客戶的那些行的Customers表,并在該表中得出預(yù)期的結(jié)果。前面我們已經(jīng)說明:其中嵌套函數(shù)的使用以及使用該函數(shù)的順序?qū)ψ罱K結(jié)果和引擎的性能有很大的影響。這在SQL中也一樣。
? ? ? ? 3)DAX作為一種編程和查詢語言
? ? ? 在SQL中,查詢語言和編程語言之間有明顯的區(qū)別:也就是說,編程語言用于在數(shù)據(jù)庫中創(chuàng)建存儲過程、視圖和其他代碼片段的指令集。每個SQL代碼都有自己的編程語句,讓程序員用代碼來豐富數(shù)據(jù)模型。
? ? ? DAX實際上并沒有區(qū)分查詢和編程。一組豐富的函數(shù)可以操作一個個列表,也可以返回一個個表。剛才在前面的查詢中看到的FILTER函數(shù)就是一個很好的例子。
? ? ? 因此,在這方面,DAX比SQL簡單。一旦將其作為一種編程語言(通常是它的第一個用法)學(xué)習(xí)它,就會知道所有需要使用它作為查詢篩選的原理。
? ? ? ? 4)DAX和SQL中的子查詢和條件
? ? ? SQL作為查詢語言最強大的特性之一是使用子查詢的特點。DAX有一些相似的概念,即在DAX的子查詢中,它們自然也是由查詢后的列表條件改變引起的。這其實對應(yīng)于我們所說的DAX中值列表與列表的交替變化,也就是是DAX的列表篩選、列表條件(列表的再次被篩選)。
? ? ? 例如,為了檢索僅購買超過100美元的客戶的總銷售額,可以將該查詢編寫為:通過簡單的嵌套函數(shù)調(diào)用,獲得相對于SQL要簡單的相同的結(jié)果:
EVALUATE
FILTER(SUMMARIZE(Customers, Customers[CustomerName],"SumOfSales",
SUM( Sales[SalesAmount] )),[SumOfSales] >100)
? ? ? 在這段代碼中,檢索CustomerName以及SumOfSales的子查詢稍后被輸入到FILTER函數(shù)中,該函數(shù)只篩選SumOfSales中大于100的行予以保留。現(xiàn)在,這段代碼對來說可能會不懂它,但是,一旦開始學(xué)習(xí)DAX,就會發(fā)現(xiàn)子查詢的使用比SQL更容易,而且它自然地流動,因為DAX是一種函數(shù)性語言。
? ? 2、DAX與MDX
? ? ? 許多BI專業(yè)人員開始學(xué)習(xí)DAX,因為它是SSAS表格的新語言,在過去,他們使用MDX語言構(gòu)建和查詢SSAS多維模型,這點上,DAX和MDX沒有多少區(qū)別。但糟糕的是,DAX的一些概念會讓你想起MDX中相似的現(xiàn)有概念,即便它們其實非常不同。
? ? ? 事實上,根據(jù)我們的經(jīng)驗,在MDX之后學(xué)習(xí)DAX是最具挑戰(zhàn)性的選擇。為了學(xué)習(xí)DAX,你需要從MDX中解放思想:試著忘記你所知道的關(guān)于多維空間的一切,并準(zhǔn)備好以全新的認識(列表的概念)來學(xué)習(xí)這門新語言。我們來了解一下:
? ? ? 1)多維和表格
? ? ? MDX在模型定義的多維空間中工作。該多維空間的形狀是基于模型中定義的維度和層次結(jié)構(gòu),進而定義多維空間的集合。在多維空間中,使用不同維度成員的交集來定義點。所以,我們認為,你需要一些時間才能理解:任何屬性層次結(jié)構(gòu)中的[All]成員,實際上都是多維空間中的一個點。
? ? ? DAX的工作方式則更簡單一些。在類似多維空間中并沒有維度,沒有成員,沒有點。換句話說,根本沒有多維空間。你可以在模型中定義層次結(jié)構(gòu),但是它們與MDX中的層次結(jié)構(gòu)完全不同。
? ? ? DAX數(shù)據(jù)空間是建立在表、列和關(guān)系之上的(即表格或列表模型)。表格模型中的每個列表既不是一個度量組,也不是一個維度:它只是一個表,要計算值,你必須掃描它、篩選它,或?qū)λ锩娴闹登蠛汀?br>? ? ? 這一切都基于兩個簡單的概念:列表和關(guān)系。
? ? ? 很快就會發(fā)現(xiàn):從建模的角度來看,數(shù)據(jù)表提供的選項比多維的要少。這種情況下,擁有較少的選項并不意味著不強大,因為有一種編程語言(即DAX),它可以豐富數(shù)據(jù)模型。
? ? ? 因為,DAX使用表、列的真正建模能力是它強大的操作列表的能力。
? ? ? 實際上,你可能已經(jīng)習(xí)慣避免在模型中使用太多的MDX。因為,一方面優(yōu)化MDX速度常常比較困難, 另一方面,DAX公式驚人的快。因此,計算的復(fù)雜性很大程度并不在數(shù)據(jù)模型中,而是在DAX公式中。所以,掌握DAX,是建模的一項根本技能。
? ? ? 2)DAX作為一種編程和查詢語言
? ? ? DAX和MDX都是編程和查詢語言。在MDX中,差異是通過MDX腳本的存在而變得清晰的。在MDX僅在腳本中使用MDX,以及一些特殊的語句(例如SCOPE語句)。當(dāng)編寫SELECT語句來檢索數(shù)據(jù)時,在查詢中使用MDX。
? ? ? 在DAX公式中則有所不同。DAX將作為一種編程語言來定義計算列(在MDX中不存在的一種新概念)和度量(類似于MDX中的成員計算)。你也可以用DAX,例如查詢語言可以使用Reporting,Services報表服務(wù)從表格模型中檢索數(shù)據(jù)。
? ? ? 然而,在DAX中并沒有特別的函數(shù),只針對這兩種語言中的一種有用。此外,還可以使用MDX查詢一個表格模型。因此,MDX的查詢與表格模型一起工作,而在設(shè)計表格模型后,DAX是你唯一的選擇。
? ? ? ? 3)DAX與SQL中的子查詢和條件
? ? ? 使用MDX,依賴于層次結(jié)構(gòu)來執(zhí)行大部分計算。例如,如果想計算上一年的銷售額,那么,必須在年度層次上檢索CurrentMember的PrevMember,并使用它重寫MDX篩選器。例如,你可以用這種方式來定義MDX的前一年計算:
CREATE MEMBER CURRENTCUBE,[Measures],[SamePeriodPreviousYearSales]? AS ([Measures],[Sales Amount],ParallelPeriod( [Date],[Calendar],[Calendar Year],1,[Date],[Calendar],CurrentMember))
? ? ? 該方法使用ParallelPeriod函數(shù),該函數(shù)返回日歷層次結(jié)構(gòu)中CurrentMember的上一期。因此,它基于模型中定義的層次結(jié)構(gòu)。
? ? ? 在DAX公式中,使用列表篩選和標(biāo)準(zhǔn)時間智能函數(shù)來寫相同的計算:[SamePeriodPreviousYearSales] :=
CALCULATE(SUM( Sales[Sales Amount] ),SAMEPERIODLASTYEAR( 'Date'[Date] ))
? ? ? 在DAX里,你可以用許多其他方法來編寫這種計算,例如,使用FILTER和其他DAX計算,但是這種思路仍然是一樣的:先篩選表,而不是使用層次結(jié)構(gòu)。這種差異是巨大的,在熟悉DAX之前,先不考慮層次結(jié)構(gòu)的計算。
? ? ? 另一個重要的區(qū)別是,在MDX中,引用該[Measures度量],[Sales Amount]和需要使用的聚合函數(shù)需要在模型中事先定義。在DAX公式中,沒有預(yù)先定義的聚合。事實上,正如可能已經(jīng)注意到的,計算的表達式是SUM(Sales[SalesAmount])。
? ? ? 預(yù)定義的聚合不是一開始就需要存在于模型中:只有在你想使用它的時候定義它即可(你總是可以創(chuàng)建一個sum of sales度量,但是我們不想不需要時,一開始就使用它)。
? ? ? 相對于MDX,DAX具有較大的靈活性。
? ? ? DAX和MDX之間的另一個重要區(qū)別是,后者大量使用數(shù)據(jù)范圍約束語句來實現(xiàn)業(yè)務(wù)邏輯(這時候,同樣使用層次結(jié)構(gòu)),而前者需要完全不同的方法,因為語言中完全缺少這種層次處理。舉個例子,如果你想在年的粒度級別上建立一個指標(biāo),在MDX中你會寫這個聲明:
SCOPE ( [Measures],[SamePeriodPreviousYearSales],[Date], [Month],[All] )
THIS = NULL: END SCOPE:
? ? ? 在DAX公式中,沒有這種范圍聲明。為了獲得相同的結(jié)果,需要檢查篩選器篩選中的篩選器是否存在,并且這種場景要復(fù)雜得多:
[SamePeriodPreviousYearSales] :=
IF(ISFILTERED( 'Date'[Month] ), CALCULATE(SUM( Sales[Sales Amount] ),SAMEPERIODLASTYEAR( 'Date'[Date] )),BLANK())
? ? ? 稍后將詳細了解該公式計算的內(nèi)容,但直觀地看,它只返回一個值,如果用戶在月級別或下級瀏覽日歷層次結(jié)構(gòu)(從月度級別開始),則返回一個空白。這個公式要比等效的MDX代碼更容易出錯。也復(fù)雜的多。說實話,層次處理是DAX公式中真正缺失的一個特征。
? ? ? 4)粒度(層級結(jié)構(gòu))計算
? ? ? 最后,在使用MDX時,你可能已經(jīng)習(xí)慣了避免粒度計算。在MDX中執(zhí)行粒度計算是非常慢的,因而總是喜歡預(yù)先計算值并利用聚合來返回結(jié)果。
? ? ? 在DAX公式中,粒度計算的速度則非???,而聚合根本不存在。在構(gòu)建數(shù)據(jù)模型的時候,這需要在適當(dāng)?shù)臅r候改變度量。
? ? ? 你可以記?。涸诖蠖鄶?shù)情況下,一個完全符合SSAS多維度的數(shù)據(jù)模型并不適合列表表格,反之亦然。
? ? ? 既便說到DAX的粒度(層級結(jié)構(gòu)),我們也只有在后續(xù)相關(guān)的內(nèi)容中看到有關(guān)DAX的粒度計算概念以及運用實例。
? ? 第29式? CALCULATE的涉及不同表之間的篩選
? ? ? ? 我們在前面草草的說了一下列表之間的列表關(guān)系,并多次提到列表關(guān)系:數(shù)據(jù)模型就是列表+關(guān)系構(gòu)成,因為DAX數(shù)據(jù)模型中的關(guān)系相對來說,一旦建立就比較固定,總是伴隨數(shù)據(jù)模型(只要不刪除它),后面也將經(jīng)常提到列表關(guān)系、因此,我們并沒有刻意的將它作為一個單獨的專題概念,雖然很有必要,但它會貫穿后面的DAX學(xué)習(xí)。作為CALCULATE系列的知識點,我們需要你有一定的DAX基礎(chǔ)將會最好。
? ? ? 你可以通過一些官方的幫助文檔,很容易就了解。
? ? ? 我們前面開始學(xué)習(xí)了一些列表篩選概念,這讓我們發(fā)現(xiàn)了一些有趣的、令人驚訝的一些結(jié)果。你可能已經(jīng)注意到,大多數(shù)情況下,我們故意只使用一個表:比如只有一個產(chǎn)品表,只需要面對同一表達式中行篩選和列表之間的交互等等。
? ? ? 事實上,數(shù)據(jù)模型很少只包含一個表。很有可能在數(shù)據(jù)模型中存在許多具有關(guān)系的表。因此,一個有趣的問題是:在兩個或多個表之間的篩選如何通過關(guān)系聯(lián)系? 此外,因為關(guān)系有一個方向,接下來,我們需要了解:關(guān)系的一端與多端發(fā)生了什么”。
? ? ? 最后,為了增加點難度,請回想一下:
? ? ? 1)關(guān)系可以是單向的,也可以是雙向的,這取決于如何定義交叉篩選器關(guān)系本身的關(guān)系方向。
? ? ? 2)如果在關(guān)系的多端創(chuàng)建一個行篩選,你希望它能讓你使用一端的列嗎?
? ? ? 3)此外,如果在關(guān)系的一端創(chuàng)建了行篩選,那么是否希望能夠從關(guān)系的多端訪問表中的列呢?
? ? ? 4)如果針對的是列表篩選呢?又如何呢? 比如希望在多個表上放置一個篩選器,并將其傳播到另一端的表中?
? ? ? 任何答案都可能是正確的,但我們感興趣的是學(xué)習(xí)DAX在這些情況下的表現(xiàn),也就是說,理解DAX語言是如何通過關(guān)系定義篩選的傳遞。
? ? ? 正如你將要學(xué)習(xí)的,在篩選和關(guān)系中有一些微妙的相互作用,學(xué)習(xí)它們,需要一些耐心。
? ? ? 為了檢查這個問題,我們設(shè)置一個場景:使用一個包含6個表的數(shù)據(jù)模型,可以在下圖中看到:

? ? ? ? 在圖中,可以看到用于學(xué)習(xí)篩選和關(guān)系的交互的數(shù)據(jù)模型。關(guān)于這個模型,有幾點需要注意:
? ? ? ? 1)從銷售表到產(chǎn)品類別表,從產(chǎn)品表和產(chǎn)品類別表開始,為一對多的關(guān)系鏈:
? ? ? ? 2)唯一的雙向關(guān)系是銷售表和產(chǎn)品表之間的關(guān)系:
? ? ? ? 3)所有剩余的關(guān)系都被設(shè)置為單向的交叉篩選方向。
? ? ? ? 既然我們已經(jīng)定義了該模型,那么,讓我們開始研究篩選是如何通過一些DAX公式來表現(xiàn)的。
? ? ? 1、行篩選和關(guān)系
? ? ? 行環(huán)境之間的相互作用和關(guān)系很容易理解,因為只需要記?。核鼈儾灰匀魏畏绞浇换?,至少不會自動交互。只在前面我們已經(jīng)提過。
? ? ? ? 假設(shè)希望在Sales表中創(chuàng)建一個計算列,其中包含存儲在事實表中的單價和產(chǎn)品表中存儲的產(chǎn)品價格之間的差異。你可以試試這個公式:
? ? ? Sales[UnitPriceVariance] = Sales[UnitPrice] - Product[UnitPrice]
? ? ? 你應(yīng)該能夠解釋該公式:這個表達式引用來自兩個不同表的兩列,期望DAX在一個行篩選中對它進行計算,因為在該表中定義了計算列 Sales[UnitPriceVariance] 。產(chǎn)品表是銷售表關(guān)系的一端(銷售表為關(guān)系的多端)。所以,可能期望能夠獲得當(dāng)前相關(guān)行的單價。
? ? ? 不幸的是,這種情況并沒有發(fā)生。Sales中的行篩選不會自動傳遞到Product--產(chǎn)品表,如果試圖使用上面的一個公式來創(chuàng)建計算列,將返回一個錯誤。
? ? ? 我們再次使用前面討論的RELATED以及RELATEDTABLE函數(shù)。
? ? ? 如果希望從關(guān)系的多端的表中訪問關(guān)系的一端的列,就像本例中的情況一樣,必須使用RELATED函數(shù)。RELATED接受一個列名稱作為參數(shù),并從當(dāng)前行篩選開始,從關(guān)系的多對一方向的一個或多個關(guān)系中找到相應(yīng)行中的列的值。你可以用下面的代碼以正確的替代前面的公式:
? ? ? Sales[UnitPriceVariance] = Sales[UnitPrice] - RELATED( Product[UnitPrice] )
? ? ? ? RELATED行為:當(dāng)行篩選在數(shù)據(jù)列表關(guān)系的多端時使用(即引用一端關(guān)系表的列值)。如果主動的行篩選在關(guān)系的一端,那么,你不能使用RELATED(從一對多方向引入數(shù)據(jù)),因為可能會被檢測到關(guān)系的許多行。
? ? ? 在這種情況下,需要使用另一個類似的函數(shù):RELATEDTABLE??梢栽陉P(guān)系的一端使用RELATEDTABLE,它會返回所有(引用的表在關(guān)系的多端)與“當(dāng)前行”相關(guān)的列的值。例如,如果要計算每個產(chǎn)品的銷售數(shù)量,可以使用以下公式, 在產(chǎn)品表里定義一個計算列:
? ? ? ? Product[NumberOfSales] =COUNTROWS(RELATEDTABLE( Sales ) )
? ? ? 這個表達式計算對應(yīng)于當(dāng)前產(chǎn)品的Sales表中的行數(shù)。該模式在處理關(guān)系的一端有行篩選時非常有用。
? ? ? 值得注意的是,RELATED 和RELATEDTABLE函數(shù)都可以遍歷一長鏈的關(guān)系來收集它們的結(jié)果:不限于單節(jié)點連接關(guān)系(一級關(guān)系)。例如,可以使用前面相同的代碼來創(chuàng)建一個列,但這一次,我們將在產(chǎn)品類別表里創(chuàng)建(這存在:Sales-->產(chǎn)品表-->產(chǎn)品類別表-->產(chǎn)品子類別表的多級關(guān)系):
? ? ? ProductCategory'[NumberOfSales] = COUNTROWS(RELATEDTABLE( Sales ) )
? ? ? 結(jié)果是該類別的銷售數(shù)量,它遍歷了從產(chǎn)品類別到產(chǎn)品子類表,然后再到產(chǎn)品表最終回到銷售表的關(guān)系鏈。
? ? ? 值得注意的是:RELATED 和 RELATEDTABLE的一般規(guī)則的唯一例外是:一對一關(guān)系。如果兩個表共享一個1:1的關(guān)系,那么,可以使用RELATED和RELATEDTABLE兩個中的任何一個,得到一個列值或一個單行的表,這取決于你用的哪一個函數(shù)。
? ? ? 對關(guān)系鏈的唯一限制是:所有的關(guān)系都必須是相同的類型(即一對多或多對一),所有的關(guān)系都朝著同一個方向。如果有兩個表,通過一對多和多對一關(guān)聯(lián),并有一個中間橋表在中間,既非一對多,也不是多對一。因此,如果使用1:1的關(guān)系作為表現(xiàn)方式的同時??梢杂幸粋€1:1的一對多的關(guān)系而不中斷關(guān)系鏈。
? ? ? 讓我們以一個例子來說明這個概念。你可能認為客戶與產(chǎn)品有關(guān),因為客戶和銷售之間存在一對多的關(guān)系,然后是銷售和產(chǎn)品之間的多對一關(guān)系。因此,關(guān)系鏈可將這兩個表連接起來。
? ? ? 然而,仔細一想,這兩種關(guān)系并不是同一方向的。我們把這種情形稱為多對多關(guān)系。換句話說,一個客戶與許多產(chǎn)品(購買的產(chǎn)品)有關(guān),而一個產(chǎn)品也可以同時與許多客戶(購買產(chǎn)品的人)有關(guān)。
? ? ? 稍后將了解如何使多對多關(guān)系工作的細節(jié)?,F(xiàn)在讓我們關(guān)注行篩選。如果嘗試通過多對多關(guān)系應(yīng)用RELATEDTABLE,結(jié)果可能不是所期望的。例如,在產(chǎn)品列中考慮一個計算列:
? ? ? Product[NumOfBuyingCustomers] =COUNTROWS(RELATEDTABLE( Customer ) )
? ? ? 我們期望看到每一行里,購買該產(chǎn)品的客戶數(shù)量。出乎意料的是,結(jié)果將永遠是18869,即數(shù)據(jù)庫中客戶的總數(shù)。也就是說,如果你想遍歷一個多對多的關(guān)系,RELATEDTABLE將不工作RELATEDTABLE無法跟隨該關(guān)系鏈(只能在關(guān)系鏈的一個方向上能正確工作),因為他們不是在同一方向:一個是一對多,另一個是多對一。因此,產(chǎn)品無法傳遞篩選客戶。
? ? ? 值得注意的是,如果公式在相反的方向,也就是說,計算每個客戶購買產(chǎn)品的數(shù)量,其結(jié)果將是正確的:為每一行不同的數(shù)字代表每個客戶采購的產(chǎn)品的數(shù)量。這種行為的原因不是一個篩選器的傳遞環(huán)境,但相反,篩選轉(zhuǎn)換在RELATEDTABLE內(nèi)隱式計算。為了完整性,我們添加了這最后的注意。還沒有時間去詳細說明,但當(dāng)你全面“理解CALCULATE和CALCULATETABLE之后,這將不是問題”。
? ? ? ? 在后面的相關(guān)函數(shù)學(xué)習(xí)中,一開始,雖然不需要刻意地記住那么多的函數(shù),只少需要記住某一個或某一類函數(shù)具有某種功能,在需要的時候能想起它。剛剛討論的兩個函數(shù),你需要記住的是:在關(guān)系鏈中使用行篩選(隱式篩選或計算),需要使用RELATED 或 RELATEDTABLE。
? ? ? ? 2、列表篩選與關(guān)系
? ? ? 我們已經(jīng)了解到:行篩選不與關(guān)系交互。如要遍歷關(guān)系,則有RELATED 或 RELATEDTABLE這兩個不同的函數(shù)可供使用,這取決于在訪問目標(biāo)表時所使用的關(guān)系的哪一方。
? ? ? 與篩選環(huán)境行為方式不同:它們以自動方式相互作用關(guān)系,以及它們有不同的行為取決于你如何設(shè)置篩選的關(guān)系。一般規(guī)則是,篩選通過關(guān)系傳遞,如果在關(guān)系本身上設(shè)置的篩選方向是同一個方向,則使傳遞可行。
? ? ? ? 我們通過使用一個簡單的數(shù)據(jù)透視表,很容易地理解這種行為。在下圖中,可以看到一個透視表瀏覽到目前為止使用的數(shù)據(jù)模型,其中定義了三個非常簡單的度量。
[NumOfSales] :? ? ? ? = COUNTROWS( Sales )
[NumOfProducts] :? = COUNTROWS( Product )
[NumOfCustomers] := COUNTROWS(Customer )

? ? ? 你可以看到篩選和關(guān)系的行為:
? ? ? 一方面,篩選器在產(chǎn)品的顏色列上(透視表中的行篩選)。Product-產(chǎn)品表與Sales- 銷售表之間是一對多關(guān)系的來源。因此,篩選器篩選從產(chǎn)品表傳遞到銷售表,你可以看到這一點。因為NumOfSales度量只計算具有特定顏色的產(chǎn)品的銷售。NumOfProducts顯示了每種顏色的產(chǎn)品數(shù)量,并且每一行(顏色)的不同值也是所期望的,因為篩選器位于我們正在計算的同一張表上。
? ? ? 另一方面,[NumofCustomers]所計算的客戶數(shù)量,總是顯示相同的值,即客戶總數(shù)。這是因為客戶和銷售之間的關(guān)系,你可以看到如圖箭頭指向的方向:客戶與銷售表之間的關(guān)系是一種單向關(guān)系。

? ? ? 篩選器從產(chǎn)品表開始,然后傳遞到銷售表(從產(chǎn)品到銷售的箭頭,這是啟用的),但是,當(dāng)它試圖傳遞給客戶表時,它沒有找到讓它繼續(xù)的箭頭方向。因此,它停了下來。
? ? ? 單向關(guān)系允許在單一方向上傳遞關(guān)系篩選,而不允許兩者同時使用。
? ? ? 你可以認為關(guān)系中的箭頭就像信號燈。如果它們被激活,那么信號燈為綠色,傳遞就會發(fā)生。相反,如果沒有啟用箭頭,則信號燈為紅色,篩選器不能傳遞。關(guān)系箭頭總是從一端到任意關(guān)系的多端。你可以選擇讓它從多端到一端。如果你讓箭頭失效,那么,傳播就不會從多端到一端。
? ? ? 如果需要篩選器從客戶表開始,可以傳遞到銷售表。你需要啟用在對應(yīng)關(guān)系中的關(guān)系箭頭。然后,從銷售表,它可以進一步傳遞到產(chǎn)品表,因為銷售表和產(chǎn)品表的關(guān)系是雙向的。
? ? ? 如果關(guān)系是單向的,則客戶表不能篩選子類別表。這是因為,產(chǎn)品和產(chǎn)品子類別之間的關(guān)系是單向的,即它只能讓篩選器在一個方向上傳遞。只要你啟動了從產(chǎn)品開始,然后到產(chǎn)品子類別的箭頭,這時,將看到篩選器傳遞。
? ? 第30式? CALCULATE的引入VALUES(初級)
? ? ? 前面的例子非常有趣,因為它展示了如何通過使用篩選的方向來計算購買產(chǎn)品的客戶數(shù)量。然而,如果你有興趣只計算客戶的數(shù)量,還有一個有趣的替代,我們作為契機,引入另一個強大的函數(shù)功能:VALUES。
? ? ? 關(guān)于VALUES函數(shù),我們在前面介紹CALCULATE的唯一值列表函數(shù)時匆匆提過。
? ? ? VALUES是一個表函數(shù),它返回一個列表,其中包含當(dāng)前在列表篩選中可見的列的所有列值。我們將在后面介紹VALUES的許多高級用法。現(xiàn)在,開始使用VALUES來了解它的行為是很有幫助的。
? ? ? 在前一個示例的透視表中,可以修改NumOfCustomers,定義以下DAX表達式:
? ? ? [NumOfCustomers]:= COUNTROWS(VALUES( Sales[CustomerKey] ))?
? ? ? 這個表達式不在Customer表里計算客戶的數(shù)量。相反,它在Sales表里計算當(dāng)前篩選下CustomerKey列的數(shù)量值。這時,它只引用了Sales表,因此,表達式并不依賴于銷售和客戶表之間的關(guān)系。當(dāng)你將篩選器放在產(chǎn)品表里時,它也總是篩選sales表,因為篩選器只從產(chǎn)品表傳遞到銷售表。
? ? ? 因此,并不是所有CustomerKey的值都是當(dāng)前可見的,只有在當(dāng)前行對應(yīng)的被Sales表篩選的產(chǎn)品(即被Sales表篩選的那部分產(chǎn)品)。
? ? ? ? 你可以理解該表達式的含義是:“計算與所選產(chǎn)品相關(guān)的有銷售的當(dāng)前客戶的數(shù)量”。因為CustomerKey的值代表了Customer--顧客數(shù),這個表達式有效地計算了購買了產(chǎn)品的顧客數(shù)量(我們經(jīng)常引用表中某個含有最大唯一值的列表,來計算對應(yīng)的其他列表)。
? ? ? 請注意:可以使用DISTINCTCOUNT實現(xiàn)與上個公式相同的結(jié)果,它計算一個列的不重復(fù)值的數(shù)量。一般來說,使用DISTINCTCOUNT比使用COUNTROWS要好,這里使用COUNTROWS和VALUES是作為一種了解方式,因為VALUES是一個非常有用的函數(shù),即使它最常用的用法,也只有在后面的內(nèi)容中才會進一步了解清楚。
? ? ? 值得注意的是,使用VALUES而不是利用關(guān)系的方向傳遞作用是有利有弊的。
? ? ? 當(dāng)然,使用VALUES在模型中設(shè)置篩選要靈活得多,因為它使用關(guān)系。因此,不僅可以使用CustomerKey來計算客戶,還可以計算客戶的任何其他屬性值(例如,客戶類別的數(shù)量等)。
? ? ? ? 這樣說,可能有一些原因迫使你使用單向篩選,或者可能需要使用VALUES以提高性能等原因。無論進行VALUES計數(shù)還是將VALUES用作篩選器,你都將在編寫DAX時經(jīng)常使用它。這將在后面的“高級列表關(guān)系處理”中更詳細地討論這些主題。
? ? ? 第31式? CALCULATE的ISFILTERED、ISCROSSFILTERED函數(shù)行為
? ? ? 在前面學(xué)習(xí)DAX列表的過程中,我們不知不覺地已經(jīng)接觸到多個DAX函數(shù)的功能與用法,這都是在一種很自然的情況下發(fā)生的。
? ? ? ? 1、本式將要介紹的ISFILTERED、ISCROSSFILTERED這兩個函數(shù),它們非常有用:可以幫助我們更好地理解列表篩選的傳遞以及運用該行為方式。
? ? ? 也可以很好地了解數(shù)據(jù)透視表計算中最有用的、以及在書寫DAX公式時需要考慮的概念之一:檢測正從DAX 內(nèi)部計算的某個值所在的層級級別。例如,了解在當(dāng)前篩選中某列的所有值是否都是可見的。
? ? ? ISFILTERED,依據(jù)參數(shù)定義的列是否直接被篩選來返回真或假;也就是說它已經(jīng)被置于行、列、切片器或篩選器中了。而且,對于當(dāng)前單元格而言篩選正在發(fā)生。? ?
? ? ? ISCROSSFILTERED,根據(jù)該列是被某個直接篩選器篩選還是由另一個篩選器自動傳遞而篩選,返回真或假。
? ? ? 此外,學(xué)習(xí)它們是介紹數(shù)據(jù)透視表計算里最有用的概念之一的好方法,也就是說,檢測從DAX內(nèi)部計算值的單元格。這兩個函數(shù)的目的是允許檢測一個列的所有值是否在當(dāng)前篩選中可見(是否是引擎需要處理的列表計數(shù))。
? ? ? ISFILTERED返回TRUE或FALSE(真或假),這取決于列作為直接篩選的一個參數(shù)傳遞,也就是說,它被放在行、列、切片器、任何篩選器以及篩選對當(dāng)前發(fā)生的行(單元格)。
? ? ? ISCROSSFILTERED返回TRUE或FALSE,這取決于該列是否有一個篩選器,該篩選器來自另一個篩選器的自動傳遞,而不是直接的篩選器。
? ? ? 本式中,我們感興趣的是使用該函數(shù)來理解篩選的傳遞。因此,我們創(chuàng)建一個虛構(gòu)的表達式,它只出于學(xué)習(xí)目的。度量定義如下:
? ? ? ? [CategoryFilter] := ISFILTERED( 'Product Category'[Category])
? ? ? 這個簡單的度量返回ISFILTERED函數(shù)應(yīng)用于(即引用)'Product Category'[Category]的值。然后我們再創(chuàng)建第二個度量,該度量與產(chǎn)品顏色列進行相同的測試。因此,代碼是:
? ? ? ? [ColorFilter] :=ISFILTERED( Product[ColorName] )
? ? ? 如果將這兩種方式都添加到一個透視表中,將Category--類別放在一個切片器中,并且在行上添加Color--顏色,結(jié)果將類似于圖:

? ? ? 圖中你可以看到,Category--類別從來沒有被篩選過,而且Color-顏色在任何地方都被篩選掉了,但是在總量上顯示正確。
? ? ? 這里的重點是:Category--類別從來沒有被篩選過。因為,即使添加了一個切片器,我們也沒有在它上面做出任何篩選。另一方面,顏色總是在行中進行篩選,因為每一行都是當(dāng)前特定的顏色,但在總量中沒有,因為列表篩選并不包含任何產(chǎn)品的選擇。
? ? ? 請注意總計的這種行為,也就是說,它不是從行和列中篩選得到的,因此,在總計上,它顯示了一個不同的值。當(dāng)你想要修改一個公式的行為時,這是非常有用的。實際上,將檢查在透表報告中結(jié)果存在的屬性,以了解正在計算的單元格是否在數(shù)據(jù)透視表的內(nèi)部,或者是在總計上。
? ? ? 如果現(xiàn)在從類別切片器中選擇一些值,結(jié)果會發(fā)生變化?,F(xiàn)在,這個類別總是有一個篩選器,事實上,切片器引入的列表篩選即使在數(shù)據(jù)透視表的總計上也是有效的。
? ? ? 當(dāng)一個直接篩選器在一個列上工作時,ISFILTERED將發(fā)揮作用。某些情況下,不顯示所有的列值,不是因為篩選了列表,而是因為在列上放置了來自另一個列的篩選器。例如,如果你篩選顏色,并計算產(chǎn)品品牌的值,得到的結(jié)果將只有當(dāng)前特定顏色的產(chǎn)品品牌。
? ? ? 當(dāng)一個列的篩選來自另一個列時,我們說這個列被交叉篩選(當(dāng)一個列上的篩選器‘來自同一個列時,我們說這個列被直接篩選),ISCROSSFILTERED函數(shù)用于檢測這個交叉篩選的場景。
? ? ? 如果使用這兩個新度量查詢數(shù)據(jù)模型,這一次,我們使用ISCROSSFILTERED篩選了顏色和類別列:
? ? ? [CrossCategory] := ISCROSSFILTERED( 'Product Category'[Category] )
? ? ? [CrossColor]:? ? ? = ISCROSSFILTERED( Product[Color] )
? ? ? 然后將得到:使用ISCROSSFILTERED可以看到交叉篩選函數(shù)結(jié)果。
? ? ? 公式中,Color--顏色是被交叉篩選的,而category類別不是。在這一點上,問題是:“為什么這個類別沒有篩選?” 當(dāng)篩選一種Color--顏色時,你可能只會看到特定Color--顏色的產(chǎn)品的類別。要回答這個問題,需要清楚,類別--[Category]列不屬于產(chǎn)品表的列,相反,它只是Product Category--產(chǎn)品類別的一部分,關(guān)系不會傳遞(關(guān)系的箭頭方向不對)。
? ? ? ? 如果更改數(shù)據(jù)模型--在從產(chǎn)品到產(chǎn)品類別的整個關(guān)系鏈上啟用雙向篩選,則結(jié)果將會不同,因為啟用雙向篩選后,代表著現(xiàn)在顯示這個類別是交叉篩選的,而不是直接篩選。
? ? ? 你已經(jīng)看到了一些ISFILTERED 和ISCROSSFILTERED的示例,主要用于理解目的,因為使用它們只是為了更好地理解列表篩選是如何通過關(guān)系傳遞的。在接下這來的內(nèi)容中,通過編寫高級DAX代碼,將了解為什么這兩個函數(shù)是如此有用。
? ? ? ? 2、列表篩選知識點回顧
? ? ? 讓我們回顧一下我們所學(xué)到的關(guān)于列表篩選計算的知識。
? ? ? 1)DAX計算篩選是通過篩選數(shù)據(jù)模型并提供當(dāng)前行的概念(當(dāng)需要訪問列值時)來修改DAX表達式的列表集然后計算;
? ? ? 2)DAX總是先篩選再計算,一般總是先引用列表,然后定義值列表;
? ? ? 3)DAX計算環(huán)境由兩部分組成:行(值列表)篩選和列表篩選。它們在所有的DAX公式中共存。當(dāng)定義計算列時,DAX會自動創(chuàng)建行篩選,你還可以使用迭代器函數(shù)以編程(定義)方式創(chuàng)建行篩選,所有迭代器都用于定義行篩選;
? ? ? 4)可以嵌套行篩選,在這種情況下,EARLIER函數(shù)有助于訪問前一行的篩選(指代為:“當(dāng)前行”);
? ? ? 5)當(dāng)使用數(shù)據(jù)透視表時,通過在其行、列、切片器和篩選器上使用字段來創(chuàng)建每個列表篩選。另一種方法是:可以通過使用CALCULATE來顯式創(chuàng)建篩選器篩選;
? ? ? 6)行篩選不會通過關(guān)系自動傳遞。這可以通過使用RELATED 和 RELATEDTABLE來手動進行傳遞。正確使用這些函數(shù)功能的前提是列表具有一對多關(guān)系: RELATED用于關(guān)系的多端,RELATEDTABLE用于關(guān)系的一端。
? ? ? 7)與行篩選不同的是,列表篩選總伴隨著關(guān)系的自動傳遞,并總是從關(guān)系的一端傳遞到另一端(一端或多端)。此外,關(guān)系還可以選擇從多端擴展到一端。根據(jù)關(guān)系數(shù)據(jù)模型的定義,一切都自動在引擎內(nèi)部發(fā)生,并不是強制傳遞;
? ? ? 8)VALUES()返回一個表,其中包含當(dāng)前篩選下可見的列的所有唯一值。你可以將生成的表用作任何迭代器的參數(shù)。? ? ? ? ? ? ? ? ? ? ? VALUES()既可以引用列表,也可以定義值列表,這取決于函數(shù)的結(jié)果。等等。
? ? ? 至此,你似乎已經(jīng)了解了DAX語言中最復(fù)雜的一些概念主題。這些概念規(guī)定了公式的所有評價流,它們是DAX語言的支柱。無論何時,如果遇到表達式計算結(jié)果不是自己希望的,很大的原因,是因為你還沒有完全理解這些規(guī)則。
? ? ? ? 正如我們在介紹中所說的,在第一次閱讀時,所有這些主題看起來都很簡單。事實上,讓他們變得復(fù)雜的是:DAX總在一個復(fù)雜的計算環(huán)境中!表達式的不同部分中可能有多個活動的計算篩選。掌握計算篩選是一種你將獲得DAX經(jīng)驗的技能,我們將在接下來的章內(nèi)容中展示許多例子來幫助你。在你自己寫出一些DAX公式之后,將直觀地知道哪些篩選被使用,以及它們需要哪些功能,這樣,你將最終掌握DAX語言。