1、DAX基礎(chǔ)語法
DAX公式一般的格式是將表名用單引號括起來哀峻,后跟用方括號括起的列名涡相,如下:
'Sales'[Quantity]
但是標準是在列引用中始終使用表名,在度量引用中始終避免使用表名剩蟀。
在以后介紹了上下文轉(zhuǎn)換之后催蝗,我們會了解到這個標準背后的基本原理
Sales[Quantity] * 2 -- 這是計算列的寫法
[Sales Amount] * 2 -- 這是度量值的寫法
'--'和'//'在DAX中表示單行注釋
多行注釋以'/*'開始,以'*/'結(jié)束育特。
1.1 DAX數(shù)據(jù)類型
DAX支持七種數(shù)據(jù)類型參與計算
DAX會在操作符需要時自動將字符串轉(zhuǎn)換為數(shù)字丙号,并將數(shù)字轉(zhuǎn)換為字符串。
例如缰冤,如果我們使用連接字符串的&操作符犬缨,DAX將其參數(shù)轉(zhuǎn)換為字符串。
下面的公式以字符串形式返回“54”:
= 5 & 4
另一方面棉浸,該公式返回一個值為9的整數(shù)結(jié)果:
= "5" + "4"
但是上述方式并不推薦怀薛,如果真想轉(zhuǎn)換數(shù)據(jù)類型,推薦顯式轉(zhuǎn)換迷郑,上面的例子可以改為:
= VALUE ( "5" ) + VALUE ( "4" )
1.2 DAX操作符
1.3 構(gòu)造表
在DAX中枝恋,我們可以直接在代碼中定義匿名表。
如果表只有一列嗡害,那么語法上只需要一個值列表—每一行一個值—由花括號分隔焚碌。
我們可以用括號分隔多行,如果表只有一列就漾,括號是可選的呐能。
例如,以下兩個定義是等價的:
{ "Red", "Blue", "White" }
{ ( "Red" ), ( "Blue" ), ( "White" ) }
如果表有多列,括號是必需的摆出。
每一列的所有行都應該有相同的數(shù)據(jù)類型;否則朗徊,DAX將自動將列轉(zhuǎn)換為一種數(shù)據(jù)類型,這種數(shù)據(jù)類型可以容納同一列的不同行中提供的所有數(shù)據(jù)類型偎漫。
{
( "A", 10, 1.5, DATE ( 2017, 1, 1 ), CURRENCY ( 199.99 ), TRUE ),
( "B", 20, 2.5, DATE ( 2017, 1, 2 ), CURRENCY ( 249.99 ), FALSE ),
( "C", 30, 3.5, DATE ( 2017, 1, 3 ), CURRENCY ( 299.99 ), FALSE )
}
表構(gòu)造函數(shù)通常與IN操作符一起使用爷恳。例如,:
'Product'[Color] IN { "Red", "Blue", "White" }
( 'Date'[Year], 'Date'[MonthNumber] ) IN { ( 2017, 12 ), ( 2018, 1 ) }
以下示例展示了使用IN操作符比較一組列(元組)
這種方式不能與比較運算符一起使用象踊,所以以下寫法是無效的
( 'Date'[Year], 'Date'[MonthNumber] ) = ( 2007, 12 )
但是温亲,我們可以用以下方式來重寫它
( 'Date'[Year], 'Date'[MonthNumber] ) IN { ( 2007, 12 ) }
1.4 條件語句
在DAX中,我們可以使用IF函數(shù)編寫條件表達式杯矩。例如:
IF (
Sales[Quantity] > 1, "MULTI", "SINGLE"
)
IF函數(shù)有三個參數(shù)栈虚,但只有前兩個是必需的。第三個選項是可選的史隆,默認為空白魂务。所以以下兩種寫法都是一樣的
IF (
Sales[Quantity] > 1, Sales[Quantity]
)
IF (
Sales[Quantity] > 1, Sales[Quantity], BLANK ()
)
2、計算列和度量值的區(qū)別
2.1 計算列
計算列是添加到模型中的新列泌射,但它不是從數(shù)據(jù)源加載的粘姜,而是通過使用DAX公式創(chuàng)建的。
計算列和表格中的其他列一樣熔酷,還可以使用計算列來定義關(guān)系孤紧。
定義計算列的DAX表達式在計算列所屬表的當前行上下文中操作。對列的任何引用都將返回該列的當前行值拒秘,我們不能直接訪問其他行的值号显。所有計算的列都占用內(nèi)存,并且都是在表處理期間計算的翼抠。
在創(chuàng)建復雜的計算列時咙轩,存放在內(nèi)存非常有用。計算復雜計算列所需的時間始終是處理時間而不是查詢時間阴颖,這樣可以獲得更好的用戶體驗活喊。不過,要注意計算列使用了寶貴的RAM量愧。
例如钾菊,如果我們有一個復雜的計算列公式,我們可能會試圖將計算步驟拆分到不同的中間列中偎肃。盡管這種方式在項目開發(fā)期間很有用煞烫,但在生產(chǎn)中卻是一個壞習慣,因為每個中間計算都存儲在RAM中累颂,浪費了寶貴的空間滞详。
如果模型是基于DirectQuery的凛俱,那么行為就會有很大的不同。在DirectQuery模式下料饥,當表格引擎查詢數(shù)據(jù)源時蒲犬,計算的列是動態(tài)計算的。這可能導致數(shù)據(jù)源執(zhí)行大量查詢岸啡,從而產(chǎn)生速度較慢的模型原叮。
例如,我們可以利用下單時間和交貨日期兩列數(shù)據(jù)巡蘸,兩列相減得出出交付訂單所需的天數(shù)奋隶,以下是計算列的公式:
Sales[DaysToDeliver] = INT ( Sales[Delivery Date] - Sales[Order Date] )
2.2 度量值
度量值是用聚合函數(shù)計算出來的值,它的結(jié)果只有一個悦荒,而計算列得出的結(jié)果是一列的值
例如唯欣,在Sales表中定義一些計算列來計算毛利率金額:
Sales[SalesAmount] = Sales[Quantity] * Sales[Net Price]
Sales[TotalCost] = Sales[Quantity] * Sales[Unit Cost]
Sales[GrossMargin] = Sales[SalesAmount] – Sales[TotalCost]
如果想顯示毛利占銷售額的百分比,可以使用以下公式創(chuàng)建一個計算列:
Sales[GrossMarginPct] = Sales[GrossMargin] / Sales[SalesAmount]
這個公式在行級別上計算正確的值逾冬,如下圖所示黍聂,但是在總體總數(shù)級別上,結(jié)果顯然是錯誤的身腻。
可以看出來,551.46%是所有毛利占比的總和匹厘,這種計算方式顯然是錯誤的嘀趟,我們應該以所有毛利的總和除以所有銷售額的總和
如果需要對聚合值進行操作,而不是逐行操作愈诚,則必須創(chuàng)建度量她按。我們使用:=來定義度量值,而不是等號=炕柔,以便在代碼中更容易區(qū)分度量和計算列酌泰。
定義GrossMarginPct作為度量值后,結(jié)果是正確的匕累,如下圖所示陵刹。
GrossMarginPct := SUM ( Sales[GrossMargin] ) / SUM (Sales[SalesAmount] )
度量值和計算列都使用DAX表達式,不同之處在于計算的環(huán)境欢嘿。
計算列的值是在數(shù)據(jù)刷新期間計算的衰琐,它使用當前行作為上下文。結(jié)果不依賴于用戶在報表上的操作炼蹦。
度量值對當前上下文定義的數(shù)據(jù)聚合進行操作羡宙。例如,在透視表中掐隐,根據(jù)透視表的行過濾源表狗热,并使用這些過濾器聚合和計算數(shù)據(jù)。換句話說,度量值總是在計算環(huán)境下對數(shù)據(jù)的聚合進行操作(關(guān)于計算上下文會在之后進一步說明)匿刮。
因此僧凰,當在度量值中使用SUM(Sales[SalesAmount])時,我們指的是篩選聚合的所有行的總和僻焚。但是允悦,當我們在計算列中使用Sales[SalesAmount]時,我們指的是當前行中SalesAmount列的值虑啤。
需要在表中定義度量值隙弛,但是并不真正屬于表格。實際上狞山,我們可以將度量值從一個表移動到另一個表全闷,而不會丟失其功能。
因為度量值在查詢時計算萍启,它不會消耗內(nèi)存和磁盤空間总珠。通常,當我們可以用兩種方式表達計算時勘纯,度量值是首選局服。應該將計算列的使用限制在少數(shù)嚴格需要它們的情況下。具有Excel經(jīng)驗的用戶通常更喜歡計算列而不是度量驳遵,因為計算列非常類似于在Excel中計算的方式淫奔。然而,在DAX中計算值的最好方法是通過度量值堤结。
此系列是對The_Definitive_Guide_to_DAX第2版的學習筆記
歡迎關(guān)注微信公眾號:紙上躬行君