DAX是微軟SQL Server分析服務(wù)(SSAS)和Microsoft Power Pivot for Excel的編程語(yǔ)言, 它是在2010年創(chuàng)建的,第一次發(fā)布了Excel 2010的PowerPivot (是的,在2010年P(guān)owerPivot拼寫是沒有空格的;這個(gè)空格在2013版介紹Power Pivot的名字時(shí)被引入)。 隨著時(shí)間的推移,DAX在Excel社區(qū)中流行起來(lái),它使用DAX在Excel中創(chuàng)建Power Pivot數(shù)據(jù)模型,以及在商業(yè)智能(BI)社區(qū)中使用DAX來(lái)構(gòu)建帶有SSAS的模型。
DAX是一種簡(jiǎn)單的語(yǔ)言。也就是說(shuō),DAX與大多數(shù)編程語(yǔ)言不同,它可能需要一些時(shí)間才能熟悉它。在我們的經(jīng)驗(yàn)中,向成千上萬(wàn)的人教授了DAX,學(xué)習(xí)DAX的基本知識(shí)是較為簡(jiǎn)單的:你可以在幾個(gè)小時(shí)內(nèi)就開始使用它。但是,當(dāng)涉及到理解高級(jí)概念,如評(píng)估上下文、迭代和上下文轉(zhuǎn)換時(shí),一切看起來(lái)都很復(fù)雜。不放棄! 要有耐心。一旦你的大腦開始消化這些概念,你就會(huì)發(fā)現(xiàn)DAX確實(shí)是一種簡(jiǎn)單的語(yǔ)言。只是需要時(shí)間來(lái)適應(yīng)。
第一個(gè)章節(jié)主要以表格和關(guān)系對(duì)數(shù)據(jù)模型進(jìn)行簡(jiǎn)單回顧。我們推薦所有經(jīng)驗(yàn)水平的讀者閱讀這一節(jié)以了解我們?cè)趨⒖嘉墨I(xiàn)中使用的術(shù)語(yǔ)。
在下一節(jié)中,我們將向那些對(duì)其他編程語(yǔ)言有一定經(jīng)驗(yàn)的讀者提供建議,即Excel、SQL和MDX。每個(gè)部分都是為已經(jīng)知道該語(yǔ)言的讀者提供的,并且可能會(huì)發(fā)現(xiàn)閱讀對(duì)DAX的快速介紹是很有用的,我們將它與各種語(yǔ)言進(jìn)行比較。如果您是一個(gè)Excel用戶,并且發(fā)現(xiàn)MDX部分幾乎不可能理解,那是完全可以預(yù)料到的。跳過(guò)這一部分,因?yàn)樗藢?duì)你來(lái)說(shuō)毫無(wú)意義的信息,然后進(jìn)入下一章,我們進(jìn)入DAX語(yǔ)言的旅程真正開始了。
理解數(shù)據(jù)模型
DAX是一種專門用于計(jì)算數(shù)據(jù)模型的業(yè)務(wù)公式的語(yǔ)言。您可能已經(jīng)知道什么是數(shù)據(jù)模型,但是如果您不熟悉它,那么就值得為數(shù)據(jù)模型和關(guān)系的描述提供一些頁(yè)面,以便創(chuàng)建一個(gè)基礎(chǔ),您可以在此基礎(chǔ)上構(gòu)建DAX知識(shí)。
數(shù)據(jù)模型是一組表,由關(guān)系鏈接
我們都知道一個(gè)表是什么:一組包含數(shù)據(jù)的行,每一行都被分成幾列。每一列都有一個(gè)數(shù)據(jù)類型,并且包含一個(gè)單獨(dú)的信息。我們通常把表中的一行稱為記錄。表格是一種方便的組織數(shù)據(jù)的方法。就其本身而言,表已經(jīng)是一個(gè)數(shù)據(jù)模型,盡管它是最簡(jiǎn)單的形式。因此,當(dāng)您在Excel工作簿中寫入姓名和數(shù)字時(shí),您正在創(chuàng)建一個(gè)數(shù)據(jù)模型。
如果您的數(shù)據(jù)模型包含許多表,那么很有可能它們是通過(guò)關(guān)系連接起來(lái)的。兩張表之間的關(guān)系。當(dāng)兩個(gè)表與一段關(guān)系聯(lián)系在一起時(shí),我們說(shuō)它們是相關(guān)的。圖形化的關(guān)系是由連接兩個(gè)表的直線表示的。圖1-1顯示了一個(gè)數(shù)據(jù)模型的示例:
關(guān)系的一些重要方面要好好學(xué)習(xí):
- 在一段關(guān)系中兩邊的表沒有相同的角色。他們被稱為關(guān)系的一方和多方。在圖1-1中,重點(diǎn)關(guān)注產(chǎn)品和產(chǎn)品子類之間的關(guān)系。單個(gè)子類別包含許多產(chǎn)品,而單個(gè)產(chǎn)品只有一個(gè)子類。因此,產(chǎn)品子類別是關(guān)系的一方(有一個(gè)子類別),而產(chǎn)品是多方(有許多產(chǎn)品)。
- 用來(lái)創(chuàng)建關(guān)系的列(通常在兩個(gè)表中都有相同的名稱)被稱為關(guān)系的鍵。在關(guān)系的一方,此列需要在每一行有一個(gè)惟一的值。在多方上,相同的值可以(通常是)在許多不同的行中重復(fù)。當(dāng)列對(duì)每一行有唯一的值時(shí),它被稱為表的鍵。通常,表格有一個(gè)作為鍵的列。
- 關(guān)系可以形成一個(gè)鏈條。每個(gè)產(chǎn)品都有一個(gè)子類別,每個(gè)子類別都有一個(gè)類別。因此,每個(gè)產(chǎn)品都有一個(gè)類別。為了檢索產(chǎn)品的類別,您需要遍歷兩種關(guān)系的鏈。圖1-1包含了一個(gè)由三個(gè)關(guān)系組成的鏈的例子,從銷售開始,一直到產(chǎn)品類別。
- 在每一段關(guān)系中,都可以有一到兩個(gè)小箭頭。在圖1-1中,您可以看到銷售和產(chǎn)品之間的兩個(gè)箭頭,而所有其他的關(guān)系都有一個(gè)箭頭。箭頭指示自動(dòng)過(guò)濾關(guān)系的方向。我們將在后面的章節(jié)中更詳細(xì)地討論這個(gè)問(wèn)題,因?yàn)榇_定過(guò)濾器的正確方向是學(xué)習(xí)的最重要的技能之一。
- 在表格數(shù)據(jù)模型中,關(guān)系只能在單列上創(chuàng)建。多列關(guān)系不被引擎支持
理解一段關(guān)系的方向
正如我們?cè)谇耙还?jié)中所說(shuō)的,每一種關(guān)系都可以有一個(gè)或兩個(gè)方向的過(guò)濾。過(guò)濾總是從關(guān)系的一方到多方。如果關(guān)系是雙向的(也就是說(shuō),它有兩個(gè)箭頭),那么過(guò)濾也會(huì)從多方到單方。
一個(gè)例子可以幫助您更好地理解這種行為。如果您根據(jù)圖1-1中所示的數(shù)據(jù)模型創(chuàng)建一個(gè)pivot表,那么在值區(qū)域中使用年數(shù)、銷售額和ProductName數(shù)之和,您將看到如圖1-2 所示的結(jié)果。
行標(biāo)簽包含年份——也就是來(lái)自日期表的列。日期是與銷售表的關(guān)系的一方,所以當(dāng)你把銷售金額的總和放在透視表上時(shí),引擎會(huì)根據(jù)年份來(lái)過(guò)濾銷售。銷售和產(chǎn)品表之間的關(guān)系是雙向的;當(dāng)你在透視表中放入產(chǎn)品名稱時(shí),你就會(huì)得到每年賣出的產(chǎn)品數(shù)量。換一種說(shuō)法,在日期上的過(guò)濾器使用一系列的關(guān)系傳播到產(chǎn)品表。
如果您現(xiàn)在通過(guò)將顏色放在行上并在值區(qū)域中添加FullDateLabel的計(jì)數(shù)來(lái)修改透視表,那么結(jié)果就有點(diǎn)難以理解了,如圖1-3所示。
行的過(guò)濾器是產(chǎn)品表中的顏色列。因?yàn)楫a(chǎn)品是與銷售關(guān)系的一方,銷售金額的總和被正確的過(guò)濾了。產(chǎn)品名稱的計(jì)數(shù)顯然是經(jīng)過(guò)過(guò)濾的,因?yàn)樗莵?lái)自于行(Product)上的同一表的計(jì)算值。錯(cuò)誤的數(shù)字是FullDateLabel的數(shù)量。事實(shí)上,它總是顯示所有行的相同的值——順便說(shuō)一下,這個(gè)數(shù)字是日期表中行的總行數(shù)。
從顏色列中產(chǎn)生的過(guò)濾器不傳播到日期的原因是,日期和銷售之間的關(guān)系有一個(gè)箭頭,從日期指向銷售。因此,即使銷售中有一個(gè)有效的過(guò)濾器,過(guò)濾器也不能傳播到日期,因?yàn)檫@種關(guān)系的類型阻止了它。
如果您改變了日期和銷售額之間的關(guān)系,以啟用雙向過(guò)濾,那么結(jié)果將是圖1-4所示的結(jié)果:
正如你所看到的,這些數(shù)字現(xiàn)在是不同的,反映了至少一種特定顏色的產(chǎn)品被售出的天數(shù)。乍一看,似乎所有的關(guān)系都應(yīng)該被定義為雙向的,以便讓過(guò)濾器在任何方向傳播,并且總是返回有意義的結(jié)果。正如您將在本書中了解到的,這并不總是正確的設(shè)計(jì)數(shù)據(jù)模型的方法。事實(shí)上,根據(jù)您所使用的場(chǎng)景,您應(yīng)該選擇正確方向的關(guān)系傳播。
DAX對(duì)于EXCEL用戶
很有可能你已經(jīng)知道了Excel公式語(yǔ)言,它有點(diǎn)像。畢竟,DAX的根基是用于Excel的Power Pivot,開發(fā)團(tuán)隊(duì)試圖讓這兩種語(yǔ)言保持類似的功能。這使得向這種新語(yǔ)言的過(guò)渡變得更加容易。然而,兩者之間有一些非常重要的區(qū)別。
單元格VS表格
在Excel中,您可以對(duì)單元執(zhí)行計(jì)算。一個(gè)單元格使用它的坐標(biāo)來(lái)引用。因此,你可以寫出如下公式
= (A1 * 1.25) - B2

使用Excel,您可以使用@ColumnName格式來(lái)引用表格中的列,其中ColumnName是您想要使用的列的名稱,而@符號(hào)的意思是“取當(dāng)前行的值”?!半m然語(yǔ)法不是很直觀,但通常你不會(huì)寫這些表達(dá)式。它們只是簡(jiǎn)單地點(diǎn)擊一個(gè)單元格,而Excel則負(fù)責(zé)為您插入正確的代碼。
您可能認(rèn)為Excel有兩種不同的執(zhí)行計(jì)算方法:您可以使用標(biāo)準(zhǔn)的單元引用(在這種情況下,單元F4的公式應(yīng)該是E4*D4),或者您可以使用列引用,如果您在一個(gè)表中計(jì)算的話。使用列引用的優(yōu)點(diǎn)是,您可以在列的所有單元格中使用相同的表達(dá)式,而Excel則用不同的公司計(jì)算每一行。
DAX在表格上工作,所以所有的公式都需要引用列。例如,在DAX中,你用這種方式寫出之前的乘法
[AllSales] := SUM ( Sales[SalesAmount] )
使用一列來(lái)獲取特定行的值或者將整個(gè)列作為一個(gè)整體,并沒有語(yǔ)法上的區(qū)別。DAX認(rèn)為您想要對(duì)列的所有值求和,因?yàn)槟诰酆掀髦惺褂昧忻ㄔ诒纠惺荢UM函數(shù)),它要求將列名作為參數(shù)傳遞。因此,雖然Excel需要顯式的語(yǔ)法來(lái)區(qū)分要檢索的兩種類型的數(shù)據(jù),但DAX以一種自動(dòng)的方式來(lái)消除歧義。至少在一開始,這可能會(huì)讓人困惑。
Excel和DAX:兩種函數(shù)式語(yǔ)言
這兩種語(yǔ)言非常相似的一個(gè)方面是,Excel和DAX都是函數(shù)式語(yǔ)言。函數(shù)式語(yǔ)言是由基本的函數(shù)調(diào)用組成的。無(wú)論是在Excel中還是在DAX中,都沒有語(yǔ)句、循環(huán)和跳躍的概念,這在許多編程語(yǔ)言中是很常見的。在DAX,一切都是一種表達(dá)。對(duì)于來(lái)自不同語(yǔ)言的程序員來(lái)說(shuō),這種語(yǔ)言的這一方面通常是一個(gè)挑戰(zhàn),但對(duì)于Excel用戶來(lái)說(shuō),這一點(diǎn)也不奇怪。
使用迭代器
對(duì)您來(lái)說(shuō)可能是新概念的一個(gè)概念是迭代器。在Excel工作時(shí),您習(xí)慣于一次執(zhí)行計(jì)算。在前面的例子中,您已經(jīng)看到,為了計(jì)算總銷售額,您已經(jīng)創(chuàng)建了一個(gè)列,其中包含了價(jià)格乘以數(shù)量,然后,作為第二步,您將它總結(jié)為計(jì)算總銷售額。這個(gè)數(shù)字將會(huì)很有用,例如,作為一個(gè)分母來(lái)計(jì)算每個(gè)產(chǎn)品的銷售百分比
使用DAX,您可以通過(guò)使用迭代器在單個(gè)步驟中執(zhí)行相同的操作。迭代器如它名字所述的:遍歷一個(gè)表,并對(duì)表的每一行執(zhí)行一個(gè)計(jì)算,聚合結(jié)果以產(chǎn)生所需的單個(gè)值。
在前面的例子中,你可以使用SUMX迭代器來(lái)計(jì)算所有銷售的總和。
[AllSales] := SUMX ( Sales, Sales[ProductQuantity] * Sales[ProductPrice] )
在這種方法中,既有優(yōu)點(diǎn)也有缺點(diǎn)。這樣做的好處是,您可以作為一個(gè)步驟執(zhí)行許多復(fù)雜的計(jì)算,而不必?fù)?dān)心添加許多列,而這些列最終只對(duì)某些特定的公式有用。另一方面,缺點(diǎn)是,使用DAX編程的視覺效果不如Excel。事實(shí)上,你不會(huì)看到列計(jì)算價(jià)格乘以數(shù)量;它只存在于計(jì)算的生命周期中。
說(shuō)實(shí)話,你仍然可以選擇創(chuàng)建一個(gè)計(jì)算的列,計(jì)算價(jià)格和數(shù)量的乘積。然而,正如您稍后將學(xué)到的,這很少是一個(gè)好的實(shí)踐,因?yàn)樗褂昧藢氋F的內(nèi)存,并且可能會(huì)減慢計(jì)算速度。
DAX需要一些理論
讓我們明確一點(diǎn):這不是編程語(yǔ)言之間的區(qū)別;這是思維模式的不同之處。就像這個(gè)星球上的任何一個(gè)人一樣,你可能已經(jīng)習(xí)慣了在web上搜索復(fù)雜的公式和解決方案模式,以解決你想要解決的問(wèn)題。當(dāng)使用Excel時(shí),很有可能你會(huì)找到一個(gè)幾乎滿足你需要的公式。你可以復(fù)制這個(gè)公式,定制它來(lái)滿足你的需要,然后使用它,不用太擔(dān)心它是如何工作的。
例如,在我每天使用的一個(gè)工作表中,我有這個(gè)公式
{=SUM(IF(('Transactions'!$B$5:$B$991>=M30)* ('Transactions'!$B$5:$B$991<=N30),1,0))}
我不太明白花括號(hào)里的公式是怎么工作的以及如何計(jì)算IF語(yǔ)句。老實(shí)說(shuō),我只記得我需要用一個(gè)奇怪的鍵盤組合來(lái)確認(rèn)它們。也就是說(shuō),它是有效的,它總是有效的,它計(jì)算的數(shù)字是感興趣的,而不是它內(nèi)部計(jì)算值的方式。因此,作為書籍的作者和DAX專家,我也屬于這一類的用戶
這種方法在Excel中工作,與DAX不兼容。您將需要學(xué)習(xí)一些理論,并在您能夠編寫良好的DAX代碼之前徹底了解評(píng)估上下文是如何工作的。如果沒有適當(dāng)?shù)睦碚摶A(chǔ),DAX將會(huì)計(jì)算像魔術(shù)這樣的值,或者它會(huì)計(jì)算出一些毫無(wú)意義的奇怪?jǐn)?shù)字。問(wèn)題不是DAX,而是你還沒有完全理解它是如何工作的
幸運(yùn)的是,DAX的理論局限于幾個(gè)重要的概念,在第四章“理解評(píng)估環(huán)境”中得到的解釋?!爱?dāng)你讀到那一章的時(shí)候,卷起你的袖子,準(zhǔn)備好一段時(shí)間回到學(xué)校。”一旦你掌握了它的內(nèi)容,DAX將不再有任何秘密,而學(xué)習(xí)它將主要是一個(gè)獲得經(jīng)驗(yàn)的問(wèn)題。然而,除非這一理論得到了充分的理解,否則請(qǐng)不要試圖更進(jìn)一步。記?。豪斫馐浅晒Φ囊话?。
DAX 對(duì)于SQL 開發(fā)人員
如果您已經(jīng)習(xí)慣了SQL語(yǔ)言,那么您已經(jīng)使用了許多表,并在列之間創(chuàng)建了連接,以便設(shè)置關(guān)系。從這個(gè)角度來(lái)看,在DAX的世界里,你會(huì)感到非常熟悉,因?yàn)樵贒AX的計(jì)算中,計(jì)算是查詢一組由關(guān)系和聚合值組成的表。
理解關(guān)系處理
SQL和DAX之間的第一個(gè)區(qū)別在于模型中的關(guān)系工作方式。在SQL中,你可以在表格之間設(shè)置外鍵來(lái)聲明關(guān)系,但是引擎在查詢中從不使用這些外鍵,除非你對(duì)它們很明確。例如,如果你有一個(gè)客戶表和一個(gè)銷售表,其中CustomerKey是客戶的主鍵和銷售中的外鍵,那么你可以編寫一個(gè)查詢,如下所列:
SELECT
Customers.CustomerName,
SUM ( Sales.SalesAmount ) AS SumOfSales
FROM
Sales INNER JOIN Customers
ON Sales.CustomerKey = Customers.CustomerKey
GROUP BY
Customers.CustomerName
即使您使用外鍵聲明了模型中的關(guān)系,您仍然需要顯式的,并在查詢中聲明聯(lián)接條件。盡管它使查詢變得更加冗長(zhǎng),但這是很有用的,因?yàn)樗试S您在不同的查詢中使用不同的聯(lián)接條件,從而使您在查詢的表達(dá)性方面有很大的自由度。
在DAX中,關(guān)系是模型的一部分,它們都是外部連接。一旦在模型中定義了,您就不再需要在查詢中指定聯(lián)接類型:當(dāng)您使用與主表相關(guān)的列時(shí),DAX在查詢中使用一個(gè)自動(dòng)的左外連接。因此,您可以在DAX中編寫以前的SQL查詢:
EVALUATE
SUMMARIZE (
Sales,
Customers[CustomerName], "SumOfSales",
SUM ( Sales[SalesAmount] )
)
因?yàn)镈AX知道銷售和客戶之間的現(xiàn)有關(guān)系,所以它會(huì)自動(dòng)跟隨模型。最后,SUMMARIZE函數(shù)需要通過(guò)客戶Customers[CustomerName]來(lái)進(jìn)行分組,但是您沒有任何關(guān)鍵字:SUMMARIZE通過(guò)選定的列來(lái)自動(dòng)分組數(shù)據(jù)。
DAX是一種函數(shù)式語(yǔ)言
SQL是一種聲明性語(yǔ)言。您可以通過(guò)聲明使用SELECT語(yǔ)句來(lái)檢索所需的數(shù)據(jù)集來(lái)定義您所需要的東西,而不必?fù)?dān)心引擎將如何實(shí)際檢索信息。另一方面,DAX是一種函數(shù)式語(yǔ)言。
在DAX中,每個(gè)表達(dá)式都是一個(gè)函數(shù)調(diào)用,而函數(shù)參數(shù)可以依次是其他函數(shù)調(diào)用。對(duì)參數(shù)的計(jì)算可能會(huì)導(dǎo)致非常復(fù)雜的查詢計(jì)劃,而DAX則執(zhí)行這些計(jì)劃來(lái)計(jì)算結(jié)果。
例如,如果你只想檢索居住在歐洲的客戶,你可以用SQL來(lái)寫:
SELECT
Customers.CustomerName,
SUM ( Sales.SalesAmount ) AS SumOfSales
FROM
Sales INNER JOIN Customers
ON Sales.CustomerKey = Customers.CustomerKey
WHERE Customers.Continent = 'Europe'
GROUP BY
Customers.CustomerName
使用DAX,您不會(huì)聲明查詢中的WHERE條件。相反,您使用一個(gè)特定的函數(shù)(FILTER)來(lái)過(guò)濾結(jié)果:
EVALUATE
SUMMARIZE (
FILTER ( Customers,
Customers[Continent] = "Europe"
),
Customers[CustomerName], "SumOfSales",
SUM ( Sales[SalesAmount] )
)
你可以看到這個(gè) FILTER是一個(gè)函數(shù):它只會(huì)返回居住在歐洲的客戶,產(chǎn)生預(yù)期的結(jié)果。你嵌套函數(shù)的順序和你使用的函數(shù)對(duì)最終結(jié)果和引擎的性能有很大的影響。這也發(fā)生在SQL中,即使在SQL中,您信任查詢優(yōu)化器來(lái)找到最優(yōu)查詢計(jì)劃。在DAX中,盡管查詢優(yōu)化器做得很好,但是程序員在編寫好的代碼方面有更多的責(zé)任。
DAX 作為一種編程和查詢語(yǔ)言
在SQL中,查詢語(yǔ)言和編程語(yǔ)言之間有明顯的區(qū)別;也就是說(shuō),用于在數(shù)據(jù)庫(kù)中創(chuàng)建存儲(chǔ)過(guò)程、視圖和其他代碼片段的指令集。每種SQL語(yǔ)法都有自己的語(yǔ)句,讓程序員用代碼豐富數(shù)據(jù)模型。另一方面,DAX在查詢和編程之間幾乎沒有區(qū)別。一組豐富的函數(shù)可以操作表,反過(guò)來(lái)又可以返回表。您剛才在前面的查詢中看到的過(guò)濾器函數(shù)就是一個(gè)很好的例子。
因此,在這方面,DAX比SQL更簡(jiǎn)單。一旦您將它作為一種編程語(yǔ)言(通常是它的第一個(gè)用法)來(lái)學(xué)習(xí),您就會(huì)知道所有需要使用它作為查詢語(yǔ)言的東西。
在DAX和SQL中的子查詢和條件
作為查詢語(yǔ)言,SQL最強(qiáng)大的特性之一是使用子查詢的選項(xiàng)。DAX也有一些類似的概念即使在DAX的子查詢中,它們自然地來(lái)自于語(yǔ)言的功能特性。
例如,在SQL中,僅為購(gòu)買了100美元以上的客戶檢索客戶和總銷售額,您可以按照以下方式編寫該查詢:
SELECT
CustomerName,
SumOfSales
FROM
(
SELECT
Customers.
CustomerName,
SUM ( Sales.SalesAmount ) AS SumOfSales
FROM
Sales INNER JOIN Customers
ON Sales.CustomerKey = Customers.CustomerKey
GROUP BY
Customers.CustomerName
)
AS SubQuery
WHERE
SubQuery.SumOfSales > 100
通過(guò)簡(jiǎn)單地嵌套函數(shù)調(diào)用,您可以在DAX中獲得相同的結(jié)果:
EVALUATE
FILTER (
SUMMARIZE (
Customers,
Customers[CustomerName], "SumOfSales",
SUM ( Sales[SalesAmount] )
),
[SumOfSales] > 100
)
在這段代碼中,檢索CustomerName和SumOfSales的子查詢隨后被輸入到一個(gè)過(guò)濾器函數(shù)中,該函數(shù)只保留SumOfSales大于100的行。現(xiàn)在,這段代碼可能看起來(lái)不可讀,但是,一旦你開始學(xué)習(xí)DAX,你會(huì)發(fā)現(xiàn)子查詢的用法要比SQL簡(jiǎn)單得多而且它自然流暢,因?yàn)镈AX是一種函數(shù)式語(yǔ)言。
DAX 對(duì)于MDX開發(fā)人員
許多BI專業(yè)人員開始學(xué)習(xí)DAX,因?yàn)樗荢SAS表格的新語(yǔ)言,在過(guò)去,他們使用MDX語(yǔ)言來(lái)構(gòu)建和查詢SSAS多維模型。如果你是其中之一,那就準(zhǔn)備好學(xué)習(xí)一種全新的語(yǔ)言:DAX和MDX不怎么共享。更糟糕的是,DAX中的一些概念會(huì)讓你想起MDX中類似的概念,即使它們是非常不同的。
事實(shí)上,根據(jù)我們的經(jīng)驗(yàn),在MDX之后學(xué)習(xí)DAX是最具挑戰(zhàn)性的選擇。為了學(xué)習(xí)DAX,你需要從MDX中解放你的思想;試著忘記你所知道的關(guān)于多維空間的一切,并準(zhǔn)備好以清晰的頭腦學(xué)習(xí)這門新語(yǔ)言。
多維模型VS表結(jié)構(gòu)模型
MDX在您的模型定義的多維空間中工作。多維空間的形狀是基于您在模型中定義的維度和層次結(jié)構(gòu)的體系結(jié)構(gòu),而這又定義了多維空間的坐標(biāo)集。不同維度的成員集合的交集定義了多維空間中的點(diǎn)。我們想你們需要花一些時(shí)間來(lái)理解任何屬性層次結(jié)構(gòu)中的所有成員實(shí)際上都是多維空間中的一個(gè)點(diǎn)。
DAX的工作方式簡(jiǎn)單得多。在多維空間中沒有維度,沒有成員,也沒有點(diǎn)。換句話說(shuō),根本就沒有多維空間。有一些層次結(jié)構(gòu),您可以在模型中定義它們,但是它們與MDX中的層次結(jié)構(gòu)非常不同。DAX空間是建立在表、列和關(guān)系之上的。表格模型中的每一個(gè)表既不是度量組也不是維度:它只是一個(gè)表,用來(lái)計(jì)算值,您必須掃描它,過(guò)濾它,或者在它內(nèi)部進(jìn)行求和。一切都基于兩個(gè)簡(jiǎn)單的表格和關(guān)系概念。
您很快就會(huì)發(fā)現(xiàn),從建模的角度來(lái)看,表格提供的選項(xiàng)比多維度的要少。在這種情況下,擁有更少的選項(xiàng)并不意味著不那么強(qiáng)大,因?yàn)槟幸环N編程語(yǔ)言(即DAX),它可以讓您豐富模型。表格的真正的建模能力是DAX的驚人速度。事實(shí)上,您可能已經(jīng)習(xí)慣了在模型中避免使用太多的MDX,因?yàn)閮?yōu)化MDX速度通常是一個(gè)挑戰(zhàn)。另一方面,DAX的速度驚人的快。因此,計(jì)算的大部分復(fù)雜性將不會(huì)出現(xiàn)在模型中,而是在DAX公式中。
DAX作為一種編程和查詢語(yǔ)言
DAX和MDX都是編程語(yǔ)言和查詢語(yǔ)言。在MDX中,MDX腳本的存在使差異變得清晰。您在MDX腳本中使用MDX,以及一些只能在腳本中使用的特殊語(yǔ)句(例如,范圍語(yǔ)句),當(dāng)您編寫檢索數(shù)據(jù)的SELECT語(yǔ)句時(shí),您可以在查詢中使用MDX。在DAX,這有點(diǎn)不同。您將使用DAX作為一種編程語(yǔ)言來(lái)定義計(jì)算出的列(MDX中不存在的新概念)和度量(類似于MDX中的計(jì)算成員)。您還可以使用DAX作為查詢語(yǔ)言,例如,使用報(bào)表服務(wù)從表格模型中檢索數(shù)據(jù)。然而,在DAX中并沒有特殊的功能,只對(duì)這兩種語(yǔ)言中的一種有用。此外,您還可以使用MDX查詢表格模型。因此,MDX的查詢部分使用表格模型,而DAX是您在編程表格模型時(shí)的唯一選擇。
層次結(jié)構(gòu)
使用MDX,您依賴于層次結(jié)構(gòu)來(lái)執(zhí)行大部分的計(jì)算。例如,如果您想要計(jì)算前一年的銷售情況,您必須檢索當(dāng)前社員在年層次結(jié)構(gòu)中的之前的社員,并使用它來(lái)重寫MDX過(guò)濾器。例如,你用這種方法來(lái)定義MDX的前一年計(jì)算:
CREATE MEMBER CURRENTCUBE.[Measures].
[SamePeriodPreviousYearSales] AS
(
[Measures].[Sales Amount],
ParallelPeriod (
[Date].[Calendar].[Calendar Year],
1,
[Date].[Calendar].CurrentMember
)
)
該方法使用parallel周期函數(shù),該函數(shù)返回日歷層次結(jié)構(gòu)中CurrentMember的表親。因此,它基于模型中定義的層次結(jié)構(gòu)。在DAX中使用過(guò)濾上下文和標(biāo)準(zhǔn)時(shí)間智能函數(shù)編寫相同的計(jì)算:
[SamePeriodPreviousYearSales] :=
CALCULATE (
SUM ( Sales[Sales Amount] ),
SAMEPERIODLASTYEAR ( 'Date'[Date] )
)
您可以用許多其他方式編寫相同的計(jì)算方法,使用FILTER和其他DAX函數(shù),但思想仍然是一樣的:您可以過(guò)濾表格,而不是使用層次結(jié)構(gòu)。這個(gè)差別是巨大的,你可能會(huì)想念層級(jí)計(jì)算直到你習(xí)慣了DAX。
另一個(gè)重要的區(qū)別是,在MDX中,您用的是 [Measures].[Sales Amount]。在模型中已經(jīng)定義了需要使用的銷售額和聚合函數(shù)。在DAX中,沒有預(yù)先定義的聚合。事實(shí)上,正如您可能已經(jīng)注意到的,計(jì)算的表達(dá)式是SUM(Sales[Sales Amount])。預(yù)先定義的聚合函數(shù)不再在模型中;您需要在您想要使用它的時(shí)候定義它(您總是可以創(chuàng)建一個(gè)度量,它包含銷售的總和,但是我們目前不想在這里言辭過(guò)多)。
DAX和MDX之間的另一個(gè)重要區(qū)別是,后者大量使用SCOPE語(yǔ)句來(lái)實(shí)現(xiàn)業(yè)務(wù)邏輯(同樣,使用層次結(jié)構(gòu)),而前者需要完全不同的方法,因?yàn)樵谡Z(yǔ)言中,層次處理是不存在的。
舉個(gè)例子,如果你想在年度水平上定義一個(gè)度量值,在MDX中你會(huì)寫下這個(gè)語(yǔ)句:
SCOPE (
[Measures].[SamePeriodPreviousYearSales],
[Date]. [Month].[All]
)
THIS = NULL;
END SCOPE;
在DAX中,沒有SCOPE語(yǔ)句。為了獲得相同的結(jié)果,您需要檢查過(guò)濾器上下文中的過(guò)濾器的存在,并且場(chǎng)景要復(fù)雜得多
[SamePeriodPreviousYearSales] :=
IF (
ISFILTERED ( 'Date'[Month] ),
CALCULATE (
SUM ( Sales[Sales Amount] ),
SAMEPERIODLASTYEAR ( 'Date'[Date] ) ),
BLANK()
)
稍后您將了解這個(gè)公式的詳細(xì)計(jì)算,但是,直觀地,只有當(dāng)用戶在月份或下面瀏覽日歷層次結(jié)構(gòu)時(shí),才會(huì)返回一個(gè)值,否則返回一個(gè)空白。這個(gè)公式比同等的MDX代碼更容易出錯(cuò)。老實(shí)說(shuō),層次處理是DAX中真正缺失的一個(gè)特性。
葉級(jí)計(jì)算
最后,在使用MDX時(shí),您可能已經(jīng)習(xí)慣了避免葉級(jí)計(jì)算。在MDX中執(zhí)行葉級(jí)計(jì)算是如此的緩慢,以至于您總是傾向于預(yù)先計(jì)算值和利用聚合來(lái)返回結(jié)果。在DAX中,葉級(jí)計(jì)算工作速度非常快,而且聚合根本不存在。這將需要在構(gòu)建數(shù)據(jù)模型的時(shí)候改變您的想法。在大多數(shù)情況下,一個(gè)完全符合SSAS多維度的數(shù)據(jù)模型并不符合表格式模型,反之亦然。