2.1 理解DAX计算

第2章 DAX简介

2.1 理解DAX计算
2.2了解计算列和度量值
2.3 变量入门
2.4 DAX表达式中的错误处理
2.5 格式化DAX代码
2.6 聚合函数和迭代函数
2.7 使用常见的DAX函数

在本章中,我们开始讨论DAX语言。在这里,您将学习该语言的语法,计算列与度量值之间的差异(在某些旧的Excel版本中也称为计算字段)以及DAX中最常用的函数。

因为这是介绍性的一章,所以它没有深入介绍许多功能。后面的章节中将更详细地讲解。现在了解功能并开始着眼于DAX语言就够了。当我们在Power BI,Power Pivot或Analysis Services中涉及数据模型的功能时,即使产品中没有该功能,我们也会使用术语Tabular(表格模型)。例如,"Tabular in DirectQuery"是指Power BI和Analysis Services中可用的DirectQuery模式但Excel中没有。

理解DAX计算

在研究更复杂的公式之前,需要学习DAX的基础知识,包括DAX语法、DAX可以处理的不同数据类型、基本运算符以及如何引用列和表,接下来的几节中将讨论这些概念。

我们使用DAX计算表中的列值,聚合、计算和搜索数据,所有计算最终都涉及表和列。因此首先要学习的语法是如何引用表中的列。

引用列的通用格式是将表名写在单引号中,然后将列名写在方括号中,如下所示:
Sales'[Quantity]

如果表名不以数字开头、不包含空格并且不是保留字(例如DateSum),则可以省略单引号。

如果在某个表中定义公式时引用该表中的列或度量值,则表名也省略。因此,[Quantity]如果写在Sales表中的计算列或度量值中是有效的列引用。尽管如此,但我们强烈建议您不要省略表名。对此我们现在不去解释它的意义所在,当您阅读第5章 " 了解CALCULATE 和CALCULATETABLE " 时,原因就显而易见。 当您阅读DAX代码时,能够区分度量值(稍后讨论)和列至关重要。实际标准是始终在列引用中使用表名,而在度量值引用中避免使用表名。您越早采用此标准,DAX用起来就越轻松。因此,应该尽快习惯这种引用列和度量值的方式:

 Sales[Quantity]    * 2 --这是一个列引用
 [Sales Amount]     * 2 --这是一个度量值引用

DAX中的注释
上次代码示例中首次出现了DAX中的注释。DAX支持单行注释和多行注释。单行注释以-或//开头,紧接着的该行的其余内容被视为注释。

= Sales[Quantity] * Sales[Net Price]     -- Single-line comment
= Sales[Quantity] * Sales[Unit Cost]     // Another example of single-line comment

最好避免在DAX度量值、计算列或计算表的表达式末尾添加注释。这些注释起初可能不可见,并且DAX 格式化器等工具可能不支持,本章稍后将对此进行讨论。
在学习了上下文转换(第5章)后,您将了解该标准的基本原理。现在,请相信我们并遵守该标准。

DAX数据类型

DAX可以处理七个不同的数字类型,随着时间的流逝,Microsoft在不同时期为相同的数据类型引入了不同的名称,造成了混乱。

表2-1中可以找到DAX各种数据类型的不同名称。

本书中,秉承数据库和商业智能社区事实上的标准,我们使用表格2- 1第一列中的名称。例如,在Power BI中,包含TRUEFALSE的列将称为TRUE / FALSE,而在SQL Server中,将其称为BIT。但是,这种类型的值的历史上最常用的名称是Boolean

表2-1 数据类型

DAX POWER BI Power Pivot和Analysis Services 对应的常规数据类型(如SQL Server) 表格对象模型(TOM)
Integer Whole Number Whole Number Integer/INT Int64
Decimal Decimal Number Decimal Number Floating point/DOUBLE double
Currency Fixed Decimal Number Currency Currency/MONNEY Decimai
DateTime DateTime, Date,Time Date Date/DATETIME dateTime
Bolean True/False True/False Boolean/BTT/ boolean
String Text Text String/NVARCHAR (MAX) string
Variant variant
Binary Binary Binary Blob/VARBINARY (MAX) binary

DAX具有强大的类型处理系统,因此我们不必担心数据类型。在DAX表达式中,计算结果数据类型取决于表达式中使用的术语。如果从DAX表达式返回的数据类型不是预期的数据类型,则必须注意,调查表达式本身中使用的术语将导致的数据类型。

例如,如果求和数据中的一项是日期,则结果也是日期;同理,如果对整数求和,则结果为整数。此行为称为运算符重载,图2-1中显示了一个示例,其中OrderDatePlusOneWeekOrder Date列的值上加7,计算结果是一个日期。
Sales[OrderDatePlusOneWeek] = Sales[Order Date] + 7

图2-1 向日期添加整数会导致日期增加相应的天数

除了运算符重载之外,DAX还会在运算符需要时,自动将字符串转换为数字,将数字转换为字符串。例如,如果我们使用""运算符来连接字符串,则DAX会将其参数转换为字符串。

以下公式以字符串形式返回" 54":
= 5&4

然而下一公式返回结果为整数9:
= "5" + "4"

计算结果值取决于运算符,而不取决于源列,源列将根据运算符的要求进行转换。尽管此行为貌似很方便,但在本章后面的内容中,您会看到在这些自动转换过程中可能发生的错误。此外,并非所有操作符都遵循此行为。例如,比较运算符不能将字符串与数字进行比较。因此,您可以将一个数字与字符串相加,但是不能将数字与字符串进行比较。你可以在这里找到一个完整的参考:
https://docs.microsoft.com/en-us/power-BI/desktop-data-types
https://docs.microsoft.com/en-us/power-bi/desktop-data-types

由于规则是如此复杂,因此建议您完全避免自动转换。如果需要进行转换,建议您控制它并使转换明确。为了更明确,前面的示例应如下所示:
= VALUE(" 5")+ VALUE(" 4")

习惯使用Excel或其他语言的人可能熟悉DAX数据类型。对数据类型的详细规定取决于引擎,并且对于Power BI,Power Pivot或Analysis Services,它们可能有所不同。您可以在以下网址找到有关Analysis Services DAX数据类型的更多详细信息:有关数据类型的注意事项非常有用。
http://msdn.microsoft.com/en-us/library/gg492146.aspx
在以下网址找到Power BI信息:
https://docs.microsoft.com/zh-cn/power-bi/desktop-data-types

Integer

DAX仅具有一种Integer数据类型(整数)可以存储64位值。DAX中整数值之间的所有内部计算也使用64位值。

Decimal

Decimal(十进制数)总是存储为双精度浮点值。请勿将此DAX数据类型与Transact-SQLdecimal and numeric数据类型混淆。SQL中DAX 的Decimal对应数据类型为Float

Currency

Currency(货币)数据类型存储固定十进制数,在Power BI中也被称为Fixed Decimal Number(固定十进制数)。它可以代表四位小数,内部存储为64位整数值除以10,000。对Currency数据类型进行加减法运算会忽略小数点后第四位的小数,而乘除法则产生一个浮点值,从而提高了计算结果的精度。通常,如果需要提供高于四位数的精度,则必须使用Decimal数据类型。
Currency数据类型的默认格式包括货币符号。我们还可以将货币格式应用于整数和十进制数,并且可以对Currency数据类型使用不带货币符号的格式。

DateTime

DAX将日期存储为DateTime类型。此格式在内部使用浮点数,其中整数部分对应于1899年12月30日以来的天数,多出的小时、分钟和秒转换为小数部分。因此,以下表达式返回当前日期加上一天(恰好是24小时):
= TODAY()+ 1
计算结果是明天的日期。如果只需要使用DateTime的日期部分,请记住使用TRUNC除去小数部分。
Power BI提供了另外两种数据类型:DateTime。在内部,它们是DateTime的简单变体。实际上,DateTime分别存储DateTime的整数或小数部分。

Boolean

Boolean数据类型(布尔)用于表示逻辑条件。例如,以下表达式定义的计算列为布尔型:
= Sales[Unit Price] > Sales[Unit Cost]
您还会看到布尔型为数字,其中TRUE等于1,而FALSE等于0。由于TRUE > FALSE,这种表示法被证明有时对排序有利。
DAX中的每个字符串都存储为Unicode字符串,其中每个字符都以16位存储。默认情况下,字符串之间的比较不区分大小写,因此两个字符串" Power BI"和" POWER BI"被视为相等。

Variant

Variant数据类型(变体)用于根据不同的条件,返回不同的数据类型。例如,以下语句既可能返回整数又可能返回字符串,因此设置为变体类型:
IF([measure]> 0,1,"N/A")
变体数据类型不能用于常规表中列的数据类型。通常DAX度量值表达式可以是Variant

Binary

Binary(二进制)数据类型在数据模型中用来存储图像或其它非结构化信息使用。它在DAX中不可用。主要是Power View使用它,在Power BI等其他工具中可能不可用。

DAX运算符

既然您已经了解了运算符在确定表达式类型中的重要性,现在来看表2-2列出的DAX中可用的运算符。

表2-2 运算符

运算符类型 符号 使用 示例
括号 () 优先顺序和参数分组 (5+2)*3
算术 + 4+2
算术 - 减/负 5-3
算术 * 4*2
算术 / 4/2
比较 = 等于 [CountryRegion] = “USA”
比较 <> 不等于 [CountryRegion] <>“USA”
比较 > 大于 [Quantity] > 0
比较 >= 大于等于 [Quantity] >= 100
比较 < 小于 [Quantity] < 0
比较 <= 小于等于 [Quantity] <= 100
文本 & 字符串连接 “Value is” & [Amount]
逻辑 && 逻辑与 [CountryRegion] = “USA”
逻辑 逻辑或 [CountryRegion] = “USA”
逻辑 IN 列表中是否包含元素 [CountryRegion] IN {“USA”, “Canada”}
逻辑 NOT 逻辑非 NOT [Quantity] > 0

此外,逻辑运算符还可用作DAX函数,其语法类似于Excel的语法。例如,我们可以编写如下表达式:

AND ( [CountryRegion] = "USA", [Quantity] > 0 )
OR ( [CountryRegion] = "USA", [Quantity] > 0 )

这些示例分别等效于以下内容:

 [CountryRegion] ="USA" && uantity]  > 0
 [CountryRegion] ="美国" ||  [Quantity]  > 0

在编写复杂条件时,使用函数而不是运算符进行布尔逻辑运算将是很有帮助的。实际上,在格式化大段代码时,格式化和可读性函数比操作符容易得多。
但是,函数的主要缺点是我们一次只能传递两个参数。因此,如果要评估的条件超过两个,则必须嵌套函数。

表构造函数

在DAX中,我们可以直接在代码中定义匿名表。如果表只有一列,则语法仅需要一列值(每行一个),并用花括号括起来。我们可以用括号来分隔多行,如果表是由一列组成的话,括号可以用也可以不用。例如,以下两个定义是等效的:

 {"Red","Blue","White"}
 {("Red" ),("Blue"),("White")}

如果表有多个列,每行的数据则必须使用括号。每列的所有行应具有相同的数据类型;否则,DAX将自动将列转换数据类型至可以容纳整列各行所有数据类型。

{
    ( "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 )
}

表构造函数通常与IN运算符一起使用。例如,以下是DAX表述中的有效语法:

'Product'[Color] IN { "Red", "Blue", "White" }
( 'Date'[Year], 'Date'[MonthNumber] ) IN { ( 2017, 12 ), ( 2018, 1 ) }

第二个示例显示使用IN运算符比较一组列(元组)的语法。这样的语法不能与比较运算符一起使用。换句话说,以下语法无效:
( 'Date'[Year], 'Date'[MonthNumber] ) = ( 2007, 12 )

但是,我们可以使用单行表构造函数和IN运算符重写,如下所示:
( 'Date'[Year], 'Date'[MonthNumber] ) IN { ( 2007, 12 ) }

条件语句

在DAX中,我们可以使用IF函数编写条件表达式。例如,我们可以写一个依据数量值是否大于1分别返回MULTI或SINGLE的表达式。

IF (
    Sales[Quantity] > 1,
    "MULTI",
    "SINGLE"
)

该IF函数有三个参数,但只有前两个是必选的。第三个是可选的,默认为BLANK。参见以下代码:

IF (
    Sales[Quantity] > 1,
    Sales[Quantity]
)

它对应于以下显式版本:

IF (
    Sales[Quantity] > 1,
    Sales[Quantity],
    BLANK ()
)
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,864评论 6 494
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,175评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,401评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,170评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,276评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,364评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,401评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,179评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,604评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,902评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,070评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,751评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,380评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,077评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,312评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,924评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,957评论 2 351

推荐阅读更多精彩内容