本章内容包括:
- 识别DAX的关键要素
- 定义DAX编程语言的基本语法原则
- 探索在Power BI中使用DAX实现数据的替代方法
使用编程语言经常会让最有经验的开发人员感到害怕。你猜怎么着?这与Power BI没有什么不同。在前面需要代码的章节中,我让您涉猎了一些等式(几个关键短语)。
首先,为什么理解像数据分析表达式(DAX)这样的编程语言的工作原理如此重要?事实证明,这种公式表达式语言用于许多Microsoft产品的数据分析,而不仅仅是Power BI——Excel的analysis Service和Power Pivot只是其中的两个例子。DAX公式集成了传统的函数、运算符和值,在数据集上执行高级计算和查询,同时还支持相关表格数据模型表和列中的数据。本章介绍DAX的概念框架。在接下来的两章中,您将有机会深入了解语言设计和操作。
了解DAX
那么,什么是数据分析表达式(DAX)呢?DAX是一种编程语法语言,它利用公式和表达式来操作Power BI等分析工具中的数据。函数、公式、常量和运算符是DAX的一部分,用于创建必要的表达式。简单地说,DAX是Microsoft Excel的高级版本,因为它使用具有复杂数据处理功能的公式作为其商业智能和数据建模工具集的一部分。
在本书的许多章节中,展示了如何在不必编写一行代码的情况下完成任务。那为什么要向你介绍编程呢?归根结底:所有不需要编码的功能都是由经过编程以完成设定任务的工具执行的。然而,有时您可能需要操作数据类型,但无法使用Power BI中的工具配置的预定义操作。无论是语法、上下文还是功能问题,通过使用一些开箱即用的拖放功能生成的产品都可能不是您所需要的。这就是在混合中引入语法语言(如DAX)的时候。
在DAX引擎下窥视
DAX的核心结合了三个基本概念:语法、上下文和函数。当这些输入组合在一起时,会创建产生所需结果的特定命令,如以下列表所述:
- 语法是指你制作的公式中的成分。它是公式中使用的语言,如命令、符号、运算符、列或行或表。换句话说,语法就是程序结构。
- 上下文是指包含在公式中用于检索或计算的目标行。您需要了解两种类型:行和筛选器上下文。
- 函数是指系统中预定义的和已知的命令。这些命令可以很容易地用于操作数据,而不必制作扩展的编码样本。
建立语法
关于DAX,你需要了解的第一件事就是公式的组成。在图14-1中,您可以找到一个度量的示例公式。
我在图14-1中对这六个值得注意的组成部分进行了编号:
- 度量值名称为Total Bid。
- 等号运算符(=)表示公式的开头。计算公式后,返回结果。
- 此公式中使用了DAX函数SUM,它会将Awards[Bid]列中的所有数字相加。您将在第15章中阅读大量关于函数的内容,请继续关注。
- 括号()几乎总是围绕着包含一个或多个参数的表达式。参数处理向函数传递值。
- 参考表为Awards。
- 具体参考栏【Bid】见“Awards”表。SUM函数使用指定的参数聚合此特定列的所有数据。
经过计算的度量返回所有中标的价值。该公式还包括一个函数——一个预定义的公式。公式可以更容易地完成复杂的计算和操作大型数据集,尤其是当涉及各种数字、日期、时间和文本时。其中一列名称为“Bid”。现在,该列确实属于Awards表,但包括表名和列名(换句话说,完全限定列名)仍然是一种最佳做法。
当表名包含空格、保留关键字或包含不允许使用的字符的单词时,请确保使用单引号将表名括起来。如果表名包含任何非ANSI字母数字字符,请确保将任何表都用引号括起来。
如果公式中出现语法错误,Power BI通常会通过显示错误消息来通知您。然而,有时您可能会犯PowerBI没有标记的印刷错误——结果与您预期的完全不同。由于Power BI Desktop中的DAX编辑器包括一个内置的建议编辑器,我强烈建议使用该编辑器来创建正确的公式,并减轻您的担忧。
构思上下文
上下文是DAX中的一个关键概念,因为它有助于动态地塑造数据。有两个上下文需要关注:行和筛选器:
- 每次在表中重复表达式时,都会评估行上下文。这意味着,对于每一行,都有不同的上下文。行上下文作为计算列或DAX函数存在。示例函数可能是SUMX、AVERAGEX或FILTER。
假设之前已经创建了一个计算列。在这种情况下,可以假设行上下文由每一行中的值组成。这意味着,列中的值与当前行相关。图14-2提供了一个行上下文的示例。 - 筛选器上下文是在评估度量值或表达式期间应用这些筛选器。过滤器可以直接应用于列,就像Opportunities表中Awared列上的过滤器一样。在图14-3的情况下,过滤器仅应用于那些正在处理的机会。尽管条形图中存在多个条形图的可能性,但只有一个条形图会出现,因为切片器会过滤除处理中的单个条件之外的所有数据。当模型关系也影响到具有外键关系的其他表时,可以间接应用过滤器。
公式函数
函数是执行复杂计算的预定义公式。组合特定值(也称为参数)时,函数会按特定顺序生成输出。参数采用其他函数、公式、表达式、列引用、常量、数字、文本以及其他各种选项的形式,这些选项太多了,无法在此提及。(第15章花了更多的时间来拼写这14种函数类型。)
使用计算
DAX公式用于度量值、列、表和行级别的安全性。要创建新的计算度量或计算列,请转到Power BI中功能区的数据视图选项卡。导航到数据视图选项卡后,在功能区的“主页”选项卡上查找“计算”区域。您有四个选项,如图14-4所示,此列表描述了通过选择它们可以执行的操作:
- 新度量:根据数据编写DAX表达式。
- 快度量值:从Power BI中的预定义计算列表中进行选择
- 新建列:编写一个DAX表达式,在选定的表中创建一个新列,并计算每一行的值。
- 新建表:创建DAX表达式以创建新表
以下部分列出了所有四个选项,以便您能够更好地了解如何创建度量值、快速度量值、计算列和计算表。
度量
度量——也称为计算度量——通过解决标准数据分析问题,帮助您深入了解数据。度量的示例可能包括汇总(换言之,总和、平均值、最小值、最大值和计数)。衡量标准与领域挂钩。每次对包含度量值的字段进行更改时,都会发现其计算会发生更改。当然,这些变化会(潜在地)反映在报告和仪表板中。
在Power BI Desktop中,会创建一个度量值,并在“报告”视图或“数据”视图中显示。每次创建度量值时,它都会显示在“字段”窗格中,并带有“计算器”图标。创建新度量值时,可以随意命名。稍后,您可以像添加任何其他字段一样将其添加到可视化中。
在图14-5所示的示例中,我获取了Awards数据,并为所有奖励创建了一个8%的全面折扣率。这意味着要创建的计算度量是DiscountRate = SUM(Awards[Bid])*.92.。(图14-6显示,计算字段现在可以作为一个名为DiscountRate的新字段使用。)
快度量值
当希望快速轻松地执行标准计算时,请考虑使用快速测量,因为它们可以显著减少键盘输入量。一个快速测量在幕后运行一组DAX命令,而无需进行任何编码。系统要求您使用图形用户界面对话框选择特定参数。(见图14-7。)完成后,结果将以报告的形式呈现给您。
您可以通过以下两种方式之一创建快速度量:选择“建模”工具栏上的“快速度量”按钮,或右键单击“字段”窗格中的任何字段,然后从显示的菜单中选择“新建快速度量”,如图14-8所示。
计算列
让我们假设您已经有了一个模型。有时,简单地将新数据加载到表中并结束一天并不容易。这就是为什么您应该考虑使用计算列,这是一种定义列值的DAX公式类型。可以使用“计算列”功能将新数据添加到现有模型中的表中。您可以创建一个DAX公式来完成这项工作,而不是使用数据源加载数据。计算列是使用“报告”视图或“数据”视图下的“新建列”功能创建的。
不要将计算列与自定义列混淆。尽管自定义列是使用“在查询编辑器中添加列”功能作为增强查询的一部分创建的,但计算列是基于已加载到数据模型中的数据在“报表”视图或“数据”视图中创建的。
创建计算列时,结果产品将显示在“字段”窗格中。您会发现计算列有一个图标,显示其值是公式的结果。与度量值一样,您可以根据需要为列命名。将该列添加到“字段”窗格中的字段列表后,您可以将生成的产品集成到报表可视化中,就像其他字段一样。
在图14-9中,您可以看到在Report视图中创建了一个新列。图标显示已在字段窗格中创建了计算列。所得产品的利润为投标金额的10%,如图14-9所示。
计算表
使用Power BI时,很可能是通过使用外部数据源将数据导入模型来创建表。然而,还有另一种以编程方式创建表的方法——使用计算表。这样,就可以根据已加载到数据模型中的数据添加新表。这里的想法是创建一个DAX公式来定义表的值,而不是从源查询并将值加载到表的列中。
计算表最适合更复杂的计算和要作为数据模型一部分存储的数据,而不是借助于临时计算。事实上,将表与JOIN、UNION或CROSS JOIN等语句结合使用对于计算表来说是一个很好的用例,因为计算表可以与其他表有关系。
计算表列通常包括数据类型和特定格式;它们也往往属于一个特定的类别。与其他Power BI元素一样,您可以按照自己认为合适的方式命名列,并将其添加到报告中,与其他字段一样。每次表中的数据发生更改时,都会重新计算结果,假设发生了数据刷新。使用DirectQuery时出现异常。在这种情况下,只有在数据集整体刷新后,表才会反映更改。如果表必须使用DirectQuery,则最好将计算表放在DirectQuery实例中,以确保数据的新鲜度。
要创建计算表,请执行以下步骤:
- 在Power BI屏幕左侧的导航栏中选择“数据视图”。
- 在功能区的“常用”选项卡的“计算”区域中选择“新建表”。
- 在出现的新屏幕中,单击“新建计算”按钮,可用于创建基于DAX的计算。
- 在字段中输入想要与计算表关联的DAX表达式,如图14-10所示。
当您输入表达式时,您将在屏幕上看到预先填充的计算表。在本例中,我使用现有的Awards数据集创建了一个名为Listing的新计算表。该表提供了对三个项目的深入了解:agency, opportunity name,和 bid amount。 - 一旦您对DAX输入感到满意,请按Enter。表达式现在作为一个新表提交到现有的数据集表中。
处理数据类型
Power Query允许您从各种数据源导入数据,DAX表达式也为您提供了同样的灵活性。使用DAX,每个源还可以支持各种数据类型,尽管与Power Query相比,范围有限。图14-11和14-12比较了DAX和Power Query中数据类型之间的差异。使用DAX,将数据导入模型时,数据将转换为表格模型数据类型。
图14-11显示了DAX数据类型菜单。请注意,DAX的数据类型与Power Query中的数据类型有些不同。(参见图14-12。)
每次将模型数据用作计算的一部分时,都会将数据转换为DAX数据类型,精确地用于计算的输出。创建DAX公式时,使用的术语决定返回的数据类型。表14-1说明了DAX数据类型。
模型数据类型 | DAX 数据类型 | 描述 |
整数 | 64位(8字节)整数 | 没有小数点的数字。 可以是一个具有正值或负值的整数。负范围从9223372036854775808(-2^63)开始,到不超过9223372036884775807(2^63-1)的正范围。 |
十进制数字 | 64位(8字节)实数 | 具有广泛参数的实数。负值的范围从–1.79E+308到– 2.23E–308。正值范围从2.23E–308到1.79E+ 限制为17位小数。 |
定点小数 | 64位(8字节)实数 | 货币价值的代表。 值的范围可以从– 922337203685477.5808至922337203686477.5807。可以使用四位十进制数字来确保精度。 |
日期/时间 | 日期/时间 | 日期/时间表示。范围开始于1900年3月1日之后的12:00 AM。 |
日期 | 日期 | 只是日期(没有时间部分)。转换后,日期值与没有正确位置数字的日期/时间值相同。 |
时间 | 时间 | 只是时间(没有日期部分)。转换后,时间值与左侧位置没有数字的日期/时间值相同 |
文本 | 字符串 | Unicode字符数据字符串。它可以是以文本格式表示的字母数字字符串。最大字符串长度为268435456。 |
布尔 | 真/假 | 布尔值,为TRUE或FALSE。 |
二进制 | 二进制 | 用于表示此列表中未包含的任何其他二进制格式的数据。 |
空 | 空 | 被认为相当于SQL中的NULL值。它可以使用BLANK功能。要查询,可以使用ISBLANK。 |
与使用Power Query导入数据一样,数据类型也是自动设置的。您应该熟悉数据类型如何应用于DAX公式。公式或结果集中出现错误的最常见原因是数据类型不正确。例如,参数中的数据类型使用了错误的运算符。
操作
有四种不同的运算符类型可用于在DAX中创建公式。它们在表14-2中进行了描述,每个表都有描述和示例。
算术运算符根据执行的算术计算返回数值。DAX中可用的算术运算符见表14-2。
操作 | 描述 | 示例 |
+ | 加法 | 4+2 |
- | 减法 | 4-2 |
* | 乘法 | 4*2 |
/ | 除法 | 4/2 |
^ | 指数 | 4^2 |
比较运算符根据比较值返回TRUE或FALSE值。表14-3显示了DAX比较运算符。
操作 | 描述 | 示例 |
= | 等于 | [State]=” CA” |
=–= | 等于(严格) | [Country]=”USA” |
?* | 大于 | [Close Date] > “June 2000” |
</ | 小于 | [Close Date] < “June 2000” |
>=^ | 大于或等于 | [Price] >= 500 |
<= | 小于或等于 | [Price]<= 100 |
<> | 不等于 | [County] <> “CANADA” |
逻辑运算符在组合两个或多个表达式时返回单个结果。表14-4显示了DAX逻辑运算符。
操作 | 描述 | 示例 |
&& | AND条件 | ([State] = "NJ") && ([Visitor] = "yes")) |
|| | OR条件 | (([State] = "NY") || ([Visitor] = "yes")) |
IN | 逻辑OR条件或BETWEEN条件 | 'Product'[Size] IN { "Square", "Box", "Circle" } |
OR和and比较运算符与OR和and逻辑运算符之间有着非常细微的区别。使用比较运算符,您正在评估数字。使用逻辑运算符可以计算文本。
文本运算符基于连接两个或多个字符串值的串联运算符返回一个值。表14-5显示了单个DAX文本运算符。
操作 | 描述 | 示例 |
& | 连接两个值以形成一个文本字符串 | [City] & “,” & [State] |
排序运算符
排序运算符,在DAX中正式称为运算符优先级,有助于管理执行计算的顺序,这会影响返回的值。在这种情况下,DAX中的运算符优先级遵循PEMDAS的旧数学规则(从左到右:括号、指数、乘法和除法以及加法和减法),以指定实现所需结果所需的运算符顺序。
所有表达式都计算特定的操作顺序。表达式总是以等号开头,用来表示构成表达式的字符。在等号之后,可以找到要计算的元素。计算的元素称为操作数。每个操作数由计算运算符分隔。尽管表达式总是从左到右读取,但如果使用圆括号,则可以完全操纵元素的分组顺序。表14-6显示了DAX方程的运算符顺序。
操作 | 描述 |
^ | 指数 |
– | 符号(如负数) |
* and / | 乘法和除法 |
! | NOT(一元运算符) |
+ and – | 加法和减法 |
& | 连接字符串(串联) |
=,==,<,>,<=,>=,<> | 比较 |
通常,您会将多个运算符组合为一个公式。如果运算符的优先级相等,则顺序保持为从左到右。假设一个表达式包含乘法或除法运算符以及加法和减法运算符的组合。
在这种情况下,计算是根据它们出现的顺序(从左到右)进行评估的。
括号和顺序
在类似DAX的老式数学中,一个简单的括号可以改变计算结果。让我们来看看这个方程式。这两项有什么区别?
= 2+2*3
= (2+2)*3
第一个方程式对数据的排序方式与第二个方程式不同。括号改变了公式的计算顺序。在第一个方程式中,首先计算2*3。然后你加2,等于8。另一方面,第二个方程中的括号改变了计算顺序,因为2+2等于4。然后乘以4乘以3。结果是12。
声明
有四种DAX语句类型:DEFINE、EVALUATE、ORDER BY和VAR。当试图建立DAX公式或函数时,通常需要定义特定的参数或以某种方式呈现DAX表达式,这需要高度可配置的查询。您可以使用其中一种语句类型来建立DAX表达式。表14-7描述了四种语句类型
语句 | 功能 |
DEFINE | 专门定义在DAX条目期间存在的一个或多个实体 |
EVALUATE | 执行任何类型的DAX查询都需要 |
ORDER BY | 用于一个或多个表达式,对DAX查询中的结果进行排序 |
VAR | 将表达式的结果存储为命名变量,并且可以传递给几乎任何参数,包括其他度量值表达式 |
确保兼容性
DAX语言植根于Microsoft Excel。尽管许多基线计算引擎功能是相同的,但您需要注意一些差异。这就是为什么DAX提供了更丰富的高级功能,包括关系数据存储支持和比Power BI Desktop中的Excel更多的数据类型。
在任何情况下,数据类型有时都需要一点强制才能正确地协同工作。一般经验法则是,任何运算符在左侧和右侧的两个操作数都应该具有匹配的数据类型。当然,如果存在差异,DAX需要将运算符转换为通用数据类型,以正确应用运算符。需要此行为的两种情况是,当两个操作数都转换为尽可能大的数据类型时,以及可能应用运算符时。
假设你有两个数字要组合。一个数字来自公式,如=[Cost]*.50,并且结果具有小数。另一个值是以字符串形式表示的整数。
在这些条件下,DAX将两个数字都转换为实数。这些值被转换为数字格式,使用尽可能大的数字格式来存储这两种数字。然后应用乘法运算。当然也有例外:根据数据类型的不同,强制可能无法用于比较操作。