【DAX學(xué)習(xí)】1、DAX的一些事兒

image.png

DAX是專門為在數(shù)據(jù)模型上計(jì)算業(yè)務(wù)公式而設(shè)計(jì)的闯割。 大家可能已經(jīng)知道什么是數(shù)據(jù)模型彻消。 如果沒有,我們將從數(shù)據(jù)模型和關(guān)系的描述開始宙拉,為建立DAX知識奠定基礎(chǔ)宾尚。


1、什么是數(shù)據(jù)模型

數(shù)據(jù)模型是一組由關(guān)系鏈接的表

我們都知道表是什么:一組包含數(shù)據(jù)的行谢澈,每行分為幾列煌贴。 每列都有一種數(shù)據(jù)類型,并且包含一條信息澳化。 我們通常將表中的一行稱為記錄崔步。 表是組織數(shù)據(jù)的便捷方法。 表雖然本身是最簡單的形式缎谷,但它本身就是數(shù)據(jù)模型井濒。 因此灶似,當(dāng)我們在Excel工作簿中編寫名稱和數(shù)字時(shí),我們正在創(chuàng)建一個(gè)數(shù)據(jù)模型瑞你。

如果數(shù)據(jù)模型包含許多表酪惭,則它們很可能通過關(guān)系鏈接在一起。 關(guān)系是兩個(gè)表之間的鏈接者甲。 當(dāng)兩個(gè)表被關(guān)聯(lián)在一起時(shí)春感,我們說它們是相關(guān)的。 在圖形上虏缸,關(guān)系由連接兩個(gè)表的線表示鲫懒。 圖1-1顯示了數(shù)據(jù)模型的示例。

(圖1-1)

以下是關(guān)系的一些重要方面:

  • 關(guān)系中的兩個(gè)表沒有相同的角色刽辙。 它們被稱為關(guān)系的單邊和多邊窥岩,分別用1和*表示。 在圖1-1中宰缤,重點(diǎn)關(guān)注產(chǎn)品和產(chǎn)品子類別之間的關(guān)系颂翼。 一個(gè)子類別包含許多產(chǎn)品,而一個(gè)產(chǎn)品只有一個(gè)子類別慨灭。 因此朦乏,產(chǎn)品子類別和產(chǎn)品的關(guān)系是1對多的關(guān)系

  • 特殊類型的關(guān)系是1:1和弱關(guān)系。 在1:1關(guān)系中氧骤,兩個(gè)表都是單邊的呻疹,而在弱關(guān)系中,兩個(gè)表都可以是多邊的筹陵。 這些特殊類型的關(guān)系并不常見诲宇。后續(xù)會討論這些關(guān)系

  • 用于創(chuàng)建關(guān)系的列在兩個(gè)表中通常具有相同的名稱,稱為關(guān)系的鍵惶翻。在關(guān)系的單邊,該列的每一行都必須具有唯一的值鹅心,并且不能包含空格吕粗。在很多情況下,相同的值可以在許多不同的行中重復(fù)旭愧。當(dāng)列的每一行都有唯一值時(shí)颅筋,該列稱為表的鍵。

  • 關(guān)系可以形成一條鏈输枯。每個(gè)產(chǎn)品都有一個(gè)子類別议泵,每個(gè)子類別都有一個(gè)類別。因此桃熄,每個(gè)產(chǎn)品都有一個(gè)類別先口。要檢索產(chǎn)品的類別,必須遍歷兩個(gè)關(guān)系的鏈。圖1-1包含一個(gè)由三個(gè)關(guān)系組成的鏈?zhǔn)纠锞瑥匿N售開始厢汹,一直到產(chǎn)品類別。

  • 在每種關(guān)系中谐宙,一個(gè)或兩個(gè)小箭頭可以確定交叉過濾的方向烫葬。圖1-1在“銷售”和“產(chǎn)品”之間的關(guān)系中顯示了兩個(gè)箭頭,而所有其他關(guān)系只有一個(gè)箭頭凡蜻。箭頭指示自動(dòng)篩選關(guān)系的方向(交叉篩選)搭综,通常是不鼓勵(lì)使用這種雙向過濾器的


2、理解關(guān)系的方向

每個(gè)關(guān)系可以具有一個(gè)單向或雙向交叉過濾器划栓。 過濾總是從關(guān)系的單邊到多邊進(jìn)行兑巾。 如果交叉過濾器是雙向的,也就是說茅姜,如果交叉過濾器上有兩個(gè)箭頭闪朱,則過濾也會從多邊到一側(cè)發(fā)生。

  • 比如我們通過圖1-2中的以下條件去篩選,會得到圖1-3的結(jié)果
圖1-2

圖1-3

這其中的原理是因?yàn)椋篊alendar Year是屬于Date表的列钻洒。 由于Date是Sales的單邊關(guān)系奋姿,因此引擎會根據(jù)年份過濾Sales。 這就是為什么顯示的數(shù)量按年份進(jìn)行過濾的原因素标。而 由于Sales和Product表之間的關(guān)系是雙向的称诗,因此發(fā)生篩選。 當(dāng)我們在報(bào)表中放置產(chǎn)品名稱進(jìn)行計(jì)數(shù)時(shí)头遭,由于每年的過濾器通過Sales表傳遞到Product表寓免,因此我們獲得了每年銷售的產(chǎn)品數(shù)量。 如果銷售和產(chǎn)品之間的關(guān)系是單向的计维,則結(jié)果將有所不同袜香。

  • 如果我們通過在行上放置“顏色”并在值區(qū)域中添加“日期計(jì)數(shù)”來修改報(bào)告,結(jié)果將有所不同鲫惶,如圖1-4所示蜈首。
圖1-4

行中的過濾器是Product表中的Color列。 由于Product處于Sales關(guān)系的一側(cè)欠母,因此正確地過濾了數(shù)量欢策。 產(chǎn)品名稱計(jì)數(shù)被過濾,因?yàn)樗歉鶕?jù)行中的表(即Sales)計(jì)算值赏淌。 而“日期計(jì)數(shù)”對于所有行踩寇,它始終顯示相同的值,即六水,Date表中的總行數(shù)俺孙。來自Color列的過濾器不會傳播到Date表辣卒,因?yàn)镈ate和Sales之間的關(guān)系是單向的。 因此鼠冕,盡管Sales上面有活動(dòng)的篩選器添寺,但篩選器無法傳播到Date,因?yàn)殛P(guān)系方向阻止了它懈费。

  • 如果我們更改Date和Sales之間的關(guān)系以啟用雙向交叉過濾计露,則結(jié)果如圖1-5所示。
image
圖1-5

用圖1-5和圖1-4對比憎乙,可以發(fā)現(xiàn)Date的計(jì)數(shù)隨著Color的不同而不同

乍一看票罐,似乎所有的關(guān)系都應(yīng)定義為雙向的,以便使過濾器沿任何方向傳播并始終返回有意義的結(jié)果泞边。 但是現(xiàn)在就可以告訴你用這種方法設(shè)計(jì)數(shù)據(jù)模型幾乎是不合適的该押,原因后面會討論


3、DAX for Excel用戶

您可能已經(jīng)知道DAX有點(diǎn)像的Excel公式語言阵谚。 畢竟蚕礼,DAX的根源是Power Pivot for Excel,開發(fā)團(tuán)隊(duì)試圖使這兩種語言保持相似梢什。 這種相似性使向這種新語言的過渡更加容易奠蹬。 但是,有一些重要的區(qū)別嗡午。

單元格VS表格

Excel對單元格執(zhí)行計(jì)算囤躁。 使用其坐標(biāo)引用一個(gè)單元格。 因此荔睹,我們可以編寫如下公式:

= (A1 * 1.25) - B2

在DAX中狸演,不存在單元格的概念。 DAX適用于表和列僻他,而不適用于單元格宵距。 因此,DAX表達(dá)式引用表和列吨拗,這意味著編寫代碼的方式有所不同消玄。 表和列的概念在Excel中不是新的。 實(shí)際上丢胚,如果通過使用“格式為表格”功能將Excel范圍定義為表格,則可以在Excel中編寫引用表格和列的公式受扳。 在圖1-6中携龟,SalesAmount列評估一個(gè)表達(dá)式,該表達(dá)式引用同一表中的列而不是工作簿中的單元格勘高。

圖1-6

而在DAX中的寫法如下:

Sales[SalesAmount] = Sales[ProductPrice] * Sales[ProductQuantity]

如上所見峡蟋,每列均以其表名為前綴坟桅。 在Excel中,我們不提供表名蕊蝗,因?yàn)镋xcel公式在單個(gè)表中起作用仅乓。 但是,DAX在包含許多表的數(shù)據(jù)模型上工作蓬戚。 我們必須指定表名夸楣,因?yàn)椴煌碇械膬闪锌赡芫哂邢嗤拿Q。

DAX中的許多功能與Excel等效的功能以相同的方式工作子漩。 例如豫喧,IF函數(shù)在DAX和Excel中的讀取方式相同:

Excel IF ( [@SalesAmount] > 10, 1, 0) 
DAX IF ( Sales[SalesAmount] > 10, 1, 0)

Excel和DAX的語法不同的一個(gè)重要方面是引用整個(gè)列的方式。對于使用過R和Python的人來說再熟悉不過了幢泼。 實(shí)際上紧显,在[@ProductQuantity]中,@表示“當(dāng)前行中的值”缕棵。 在DAX中孵班,無需指定值必須來自當(dāng)前行,因?yàn)檫@是該語言的默認(rèn)行為招驴。 在Excel中篙程,我們可以通過刪除@符號來引用整個(gè)列(即該列中的所有行)。 如圖1-7所示

圖1-7

AllSales列的值在所有行中都相同忽匈,因?yàn)樗荢alesAmount列的總計(jì)房午。 換句話說,在當(dāng)前行中的列的值與整個(gè)列的值之間在語法上存在差異丹允。DAX是不同的郭厌。 在DAX中,這是編寫圖1-7的AllSales表達(dá)式的方式:

AllSales := SUM ( Sales[SalesAmount] )

檢索特定行的列的值與整體使用列之間在語法上沒有區(qū)別雕蔽。 DAX理解我們要對列的所有值求和折柠,因?yàn)槲覀冊诰酆虾瘮?shù)(在本例中為SUM函數(shù))中使用列名,這需要將列名作為參數(shù)傳遞批狐。 因此扇售,盡管Excel需要明確的語法來區(qū)分要檢索的兩種類型的數(shù)據(jù),但DAX會自動(dòng)進(jìn)行歧義消除嚣艇。


4承冰、Excel and DAX:兩種函數(shù)式語言

兩種語言相似的一個(gè)方面是Excel和DAX都是函數(shù)式語言。 功能語言基本上是由函數(shù)調(diào)用的表達(dá)式組成食零。 在Excel和DAX中困乒,盡管語句,循環(huán)和跳轉(zhuǎn)的概念在許多編程語言中都是通用的贰谣,但它們并不存在娜搂。 在DAX中迁霎,一切都是表達(dá)式。

DAX中的迭代器

在Excel中工作時(shí)百宇,一次只能執(zhí)行一次計(jì)算考廉。 前面的示例表明,要計(jì)算銷售總額携御,我們創(chuàng)建一個(gè)包含價(jià)格乘以數(shù)量的列昌粤。 然后,作為第二步因痛,我們對其求和以計(jì)算總銷售額婚苹。 例如,該數(shù)字可用作計(jì)算每個(gè)產(chǎn)品的銷售百分比的分母鸵膏。

使用DAX膊升,您可以使用迭代器在單個(gè)步驟中執(zhí)行相同的操作。 迭代器完全按照其名稱的含義進(jìn)行操作:它遍歷一個(gè)表并在表的每一行上執(zhí)行計(jì)算谭企,將結(jié)果匯總以產(chǎn)生所請求的單個(gè)值廓译。使用前面的示例,我們現(xiàn)在可以使用SUMX迭代器計(jì)算所有銷售額的總和:

AllSales := SUMX (
Sales, Sales[ProductQuantity] * Sales[ProductPrice]
)

這種方法既有優(yōu)點(diǎn)又有缺點(diǎn)债查。

優(yōu)點(diǎn)是我們可以在一個(gè)步驟中執(zhí)行許多復(fù)雜的計(jì)算非区,而不必?fù)?dān)心添加只會對特定公式有用的列。缺點(diǎn)是盹廷,與使用Excel進(jìn)行編程相比征绸,使用DAX進(jìn)行編程的視覺效果更差。 確實(shí)俄占,我們沒有看到計(jì)算價(jià)格乘以數(shù)量的列管怠; 它僅是整個(gè)計(jì)算的一部分。

其實(shí)我們可以創(chuàng)建一個(gè)計(jì)算列來計(jì)算價(jià)格乘以數(shù)量的乘積缸榄。但是渤弛,除非使用DirectQuery和Aggregations,否則它會占用內(nèi)存甚带,并且會減慢計(jì)算速度

5她肯、學(xué)習(xí)DAX的理論

事實(shí)上,DAX要求首先學(xué)習(xí)理論而并不是編程語言之間的區(qū)別鹰贵。在編寫DAX代碼之前晴氨,我們需要學(xué)習(xí)DAX理論并徹底理解evaluation contexts是如何工作的,不然我們會一臉懵逼碉输。所以在我們對evaluation contexts沒有了解之前籽前,最好不要深入學(xué)習(xí)下去。不過對于這些概念后面都要介紹

6、DAX for SQL使用者

如果習(xí)慣使用SQL語言聚假,那么你已經(jīng)使用過許多表并創(chuàng)建了列之間的連接來設(shè)置關(guān)系。

實(shí)際上闰非,DAX中的計(jì)算就是查詢一組由關(guān)系連接的表和值膘格。

關(guān)系的處理

SQL和DAX之間的第一個(gè)區(qū)別是模型中關(guān)系的工作方式。

在SQL中财松,我們可以在表之間設(shè)置外鍵來聲明關(guān)系瘪贱,但是引擎永遠(yuǎn)不會在查詢中使用這些外鍵,除非我們顯式地使用它們辆毡。例如菜秦,如果我們有一個(gè)Customers表和一個(gè)Sales表,其中CustomerKey是Customers中的主鍵和Sales中的外鍵舶掖,我們可以編寫以下查詢:

SELECT Customers.CustomerName,  SUM  ( Sales.SalesAmount )  AS SumOfSales 
FROM Sales
 INNER  JOIN Customers 
ON Sales.CustomerKey = Customers.CustomerKey 
GROUP  BY Customers.CustomerName

盡管我們使用外鍵在表之間聲明關(guān)系球昨,但仍然需要顯式地在查詢中聲明連接條件。雖然這種方法使查詢更加冗長眨攘,但它很有用主慰,因?yàn)榭梢栽诓煌牟樵冎惺褂貌煌倪B接條件,從而在表達(dá)查詢的方式上有很大的自由鲫售。

在DAX中共螺,關(guān)系是模型的一部分,它們都屬于外連接情竹。當(dāng)它們在模型中定義時(shí)藐不,我們不再需要在查詢中指定連接類型,只要使用與主表相關(guān)的列秦效,DAX就會在查詢中使用自動(dòng)左外連接雏蛮。因此,在DAX中棉安,您將按照如下方式編寫之前的SQL查詢:


EVALUATE 
SUMMARIZECOLUMNS ( 
       Customers[CustomerName], "SumOfSales", SUM ( Sales[SalesAmount] )
)

因?yàn)镈AX知道銷售和客戶之間的現(xiàn)有關(guān)系底扳,所以它會按照模型自動(dòng)進(jìn)行加入。

DAX是一種函數(shù)式語言

SQL是一種聲明性語言贡耽。我們可以通過使用SELECT語句聲明要檢索的數(shù)據(jù)集來定義所需的內(nèi)容衷模,而不必?fù)?dān)心引擎如何實(shí)際檢索信息。

而DAX是一種函數(shù)式語言蒲赂。在DAX中阱冶,每個(gè)表達(dá)式都是一個(gè)函數(shù)調(diào)用,而且函數(shù)參數(shù)也可以是其他函數(shù)執(zhí)行出來的結(jié)果滥嘴。參數(shù)的計(jì)算可能導(dǎo)致DAX執(zhí)行復(fù)雜的查詢計(jì)劃來計(jì)算結(jié)果木蹬。

例如,如果我們只想檢索住在歐洲的客戶若皱,我們可以編寫這個(gè)查詢

在SQL:


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镊叁,我們不會在查詢中聲明WHERE條件尘颓。相反,我們使用一個(gè)特定的函數(shù)(FILTER)來獲取結(jié)果:


EVALUATE 
SUMMARIZECOLUMNS (
      Customers[CustomerName], FILTER(
        Customers, Customers[Continent] = "Europe" ), 
     "SumOfSales", SUM ( Sales[SalesAmount] )
)

DAX是一種編程和查詢語言

在SQL中晦譬,查詢語言和編程語言之間存在明顯的區(qū)別——即用于在數(shù)據(jù)庫中創(chuàng)建存儲過程疤苹、視圖和其他代碼的指令集。

每種SQL語言都有自己的語句敛腌,以便程序員使用代碼豐富數(shù)據(jù)模型卧土。然而,DAX實(shí)際上沒有區(qū)分查詢和編程像樊。一組豐富的函數(shù)可以操作表尤莺,并反過來返回表。

DAX和SQL中的子查詢和條件

作為查詢語言的SQL最強(qiáng)大的特性之一是可以選擇使用子查詢生棍。

DAX具有類似的概念颤霎。然而,對于DAX子查詢足绅,它們源于語言的函數(shù)特性捷绑。

例如,要檢索購買價(jià)值超過100美元的客戶的客戶和總銷售額氢妈,我們可以用SQL編寫這個(gè)查詢:

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

我們可以在DAX中通過嵌套函數(shù)調(diào)用得到相同的結(jié)果:

EVALUATE 
FILTER (
  SUMMARIZECOLUMNS ( 
      Customers[CustomerName], 
     "SumOfSales", SUM ( Sales[SalesAmount] ) 
), 
  [SumOfSales] > 100
)

此系列是對The_Definitive_Guide_to_DAX第2版的學(xué)習(xí)筆記

微信公眾號:紙上躬行君

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末粹污,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子首量,更是在濱河造成了極大的恐慌壮吩,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件加缘,死亡現(xiàn)場離奇詭異鸭叙,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)拣宏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門沈贝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人勋乾,你說我怎么就攤上這事宋下。” “怎么了辑莫?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵学歧,是天一觀的道長。 經(jīng)常有香客問我各吨,道長枝笨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮横浑,結(jié)果婚禮上剔桨,老公的妹妹穿的比我還像新娘。我一直安慰自己徙融,他們只是感情好领炫,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著张咳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪似舵。 梳的紋絲不亂的頭發(fā)上脚猾,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天,我揣著相機(jī)與錄音砚哗,去河邊找鬼龙助。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蛛芥,可吹牛的內(nèi)容都是我干的提鸟。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼仅淑,長吁一口氣:“原來是場噩夢啊……” “哼称勋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起涯竟,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤赡鲜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后庐船,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體银酬,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年筐钟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了揩瞪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,030評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡篓冲,死狀恐怖李破,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情纹因,我是刑警寧澤喷屋,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站瞭恰,受9級特大地震影響屯曹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一恶耽、第九天 我趴在偏房一處隱蔽的房頂上張望密任。 院中可真熱鬧,春花似錦偷俭、人聲如沸浪讳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽淹遵。三九已至,卻和暖如春负溪,著一層夾襖步出監(jiān)牢的瞬間透揣,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工川抡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留辐真,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓崖堤,卻偏偏與公主長得像侍咱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子密幔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評論 2 355