第1章 什么是DAX?
1.1 理解數(shù)據(jù)模型
1.2 DAX FOR EXCEL用戶
1.3 DAX for SQL開發(fā)人員
1.4 DAX for MDX開發(fā)人員
1.5 DAX FOR POWER BI 用戶
DAX for MDX開發(fā)人員
許多商業(yè)智能專業(yè)人員開始學(xué)習(xí)DAX,因為它是Tabular的新語言。過去,他們使用MDX語言來構(gòu)建和查詢Analysis Services多維模型。如果您是其中的一員,請準(zhǔn)備學(xué)習(xí)一種全新的語言:DAX和MDX并沒有太多共同之處。更糟糕的是,DAX中的某些概念會讓您想起MDX中類似的現(xiàn)有概念,盡管它們有所不同。
根據(jù)我們的經(jīng)驗,發(fā)現(xiàn)在學(xué)習(xí)MDX之后學(xué)習(xí)DAX是最具挑戰(zhàn)性的選擇。要學(xué)習(xí)DAX,您需要從MDX上解放思想。嘗試忘記關(guān)于多維空間的所有知識,并準(zhǔn)備以清晰的頭腦學(xué)習(xí)這種新語言。
多維與表格
MDX在模型定義的多維空間中工作。多維空間的形狀基于模型中定義的維和層次結(jié)構(gòu)的體系結(jié)構(gòu),而這又定義了多維空間的坐標(biāo)集。不同維數(shù)的成員集的相交定義了多維空間中的點。您可能已經(jīng)花了一些時間意識到任何屬性層次結(jié)構(gòu)的[All]成員確實是多維空間中的一個點。
DAX以更簡單的方式工作。多維空間中沒有維,沒有成員,也沒有點。換句話說,根本沒有多維空間。我們可以在模型中定義層次結(jié)構(gòu),但它們與MDX中的層次結(jié)構(gòu)不同。DAX空間建立在表,列和關(guān)系之上。表格模型中的每個表既不是度量值組也不是維:它只是一個表,要計算值,請對其進(jìn)行掃描,篩選或?qū)ζ渲械闹登蠛?。一切都基于表和關(guān)系這兩個簡單的概念。
您很快就會發(fā)現(xiàn),從建模的角度來看, Tabular提供的選項少于多維。在這種情況下,擁有較少的選項并不意味著功能不那么強(qiáng)大,因為您可以使用DAX作為編程語言來豐富模型。Tabular真正的建模能力是DAX的驚人速度。實際上,您可能會嘗試避免在模型中過度使用MDX,因為優(yōu)化MDX速度通常是一個挑戰(zhàn)。另一方面,DAX非??臁R虼?,大多數(shù)計算復(fù)雜性不在模型中,而在DAX公式中。
DAX作為一種編程和查詢語言
DAX和MDX都是編程語言和查詢語言。在MDX中,通過MDX腳本的存在可以清楚地看出差異。您可以在MDX腳本中使用MDX以及幾個只能在腳本中使用的特殊語句,例如SCOPE語句。在編寫SELECT檢索數(shù)據(jù)的語句時,在查詢中使用MDX。在DAX中,這有些不同。您可以使用DAX作為編程語言來定義計算列,計算表和度量值。計算列和計算表的概念是DAX的新增功能,在MDX中不存在。度量值與MDX中的計算成員相似。您還可以將DAX用作查詢語言,例如,使用Reporting Services從表格模型中檢索數(shù)據(jù)。但是,DAX函數(shù)沒有特定的作用,可以在查詢和計算表達(dá)式中使用。此外,您還可以使用MDX查詢表格模型。因此,MDX的查詢部分適用于表格模型,而DAX是表格模型編程的唯一選擇。
層次結(jié)構(gòu)
使用MDX,您可以依靠層次結(jié)構(gòu)來執(zhí)行大多數(shù)計算。如果要計算上一年的銷售額,則必須在Year層次結(jié)構(gòu)中檢索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ù)返回Calendar層次結(jié)構(gòu)上CurrentMember的表親。因此,它基于模型中定義的層次結(jié)構(gòu)。我們將使用篩選上下文和標(biāo)準(zhǔn)時間智能函數(shù)在DAX中編寫相同的計算:
SamePeriodPreviousYearSales :=
CALCULATE (
SUM ( Sales[Sales Amount] ),
SAMEPERIODLASTYEAR ( 'Date'[Date] )
)
我們可以使用FILTER和其他DAX函數(shù)以許多其他方式編寫相同的計算,但是想法仍然相同:我們不使用層次結(jié)構(gòu),而是過濾表。這種差異是巨大的,在您習(xí)慣DAX之前,您可能會錯過層次結(jié)構(gòu)計算。
另一個重要的區(qū)別是,在MDX中,您引用了[Measures].[Sales Amount],并且模型中已經(jīng)定義了您需要使用的聚合函數(shù)。在DAX中,沒有預(yù)定義的聚合。實際上,您可能已經(jīng)注意到,要計算的表達(dá)式是SUM(Sales [Sales Amount])。預(yù)定義的聚合不再存在于模型中。每當(dāng)需要使用它時,我們都需要對其進(jìn)行定義。我們總是可以創(chuàng)建一個計算銷售額之和的量度值,但這將超出本節(jié)的范圍,稍后將在書中進(jìn)行解釋。
DAX和MDX之間的另一個重要區(qū)別是,MDX大量使用SCOPE語句來實現(xiàn)業(yè)務(wù)邏輯(再次使用層次結(jié)構(gòu)),而DAX需要完全不同的方法。實際上,該語言完全沒有層次結(jié)構(gòu)處理。
例如,如果我們想清除一項Year級別的度量值,在MDX中,我們將編寫以下語句:
SCOPE ( [Measures].
[SamePeriodPreviousYearSales], [Date].[Month].
[All] )
THIS = NULL;
END SCOPE;
DAX沒有類似SCOPE語句的內(nèi)容。為了獲得相同的結(jié)果,我們需要檢查篩選上下文中是否存在篩選,并且場景要復(fù)雜得多:
SamePeriodPreviousYearSales :=
IF (
ISINSCOPE ( 'Date'[Month] ),
CALCULATE (
SUM ( Sales[Sales Amount] ),
SAMEPERIODLASTYEAR ( 'Date'[Date] )
),
BLANK ()
)
直觀地,僅當(dāng)用戶在月份級別或更低級別瀏覽日歷層次結(jié)構(gòu)時,此公式才返回一個值。否則,它返回BLANK。稍后,您將詳細(xì)了解此公式的計算結(jié)果。它比等效的MDX代碼更容易出錯。老實說,層次處理是DAX真正缺少的功能之一。
葉級計算
最后,在使用MDX時,您可能習(xí)慣于避免進(jìn)行葉級計算。事實證明,在MDX中執(zhí)行葉級計算是如此之慢,以至于您總是喜歡預(yù)先計算值并利用聚合來返回結(jié)果。在DAX中,葉級計算的工作速度非常快,并且聚合有不同的用途,僅對大型數(shù)據(jù)集有用。這需要在構(gòu)建數(shù)據(jù)模型時改變觀念。在大多數(shù)情況下,完全適合SSAS多維數(shù)據(jù)模型不適用于表格,反之亦然。