本章内容包括:
在第14章和第15章中,我将讨论DAX的ABC。在这些章节中,提到了创建公式的步骤,这样您就可以创建更复杂的计算,以帮助为组织提供更好的见解。本章通过帮助您更好地理解在Power BI中编码和调试DAX公式背后的技术元素来结束循环。
在学习编程中,首先要学习的是如何使用变量。你猜怎么着?变量也是DAX中的一个基本构造。您可以在公式表达式中声明DAX变量。只要您至少声明一个变量,就会使用RETURN子句来定义表达式。然后,结果引用变量。
出于多种原因,您希望在开始编程时使用变量,无论是语法、上下文还是功能。这里有几个
如果您的数据模型基于计算类型、计算表或计算列,或者是在Power BI中测量的,您会发现创建公式有一个标准约定。
一个公式有一个明确的结构,从一个定义的名称开始,后面是一个等号,然后是一个DAX公式。以下是一个示例:
让我们来看一个假设的例子。与Awarded表数据重复的Awarded Status计算表的定义为
Awarded Status = 'Awarded'
DAX公式由几个变量和一个等号组成。恰恰相反!首先,DAX表达式旨在返回一个结果——一个表对象或一个度量值。让我们再细分一下。如果您有一个计算的表公式,则结果是返回的表对象。相反,计算列和度量值公式都返回奇异值。
让我们后退一步。一个公式能有什么?如表16-1所述,一个可以具有所有元素。
功能 | 描述 |
---|---|
函数 | 职能实现特定目标。函数有一个允许传递变量的参数。公式可能使用函数调用,并且经常需要函数内部的函数。函数名是一种带有条件的公式类型,条件后面应始终跟有括号。 在每个括号中,都传递了一个变量。 |
运算符 | 运算符执行算术计算、比较值、处理字符串以及测试不同状态的条件。 |
变量 | 公式可以使用变量将结果存储为计算表达式的一部分。 |
空白字符 | 使用DAX,一些字符可以帮助用户格式化公式,使其更容易理解表达式。 不同的空白字符包括空格、制表符和回车符。您不一定需要将空格作为公式逻辑的一部分。这不会影响表现。然而,它将对格式风格和一致性产生积极影响。 |
对模型对象的引用 | 公式引用表、列和度量值。公式不能引用层次结构或层次结构级别。因此,对于表引用,表名必须包含在一个单引号内。同样,列引用需要方括号内的一个封闭部分。在特定条件下,列名前面可以加上其表名。最后,度量值名称必须始终包含在方括号内。 |
隐式度量是允许视觉效果汇总模型列数据的自动行为。显式数据(专门称为度量)是可以添加到模型中的计算。
每当在字段窗格中看到西格玛符号(∑)时,都应该提醒用户或数据建模人员
在图16-1中,Awards表只包括可以汇总的字段,包括AwardID计算列。
通过使用DAX将“汇总”属性设置为“不汇总”或特定的聚合函数,可以控制列汇总数据的方式。将“汇总”属性设置为“不汇总”时,西格玛符号将忽略“字段”窗格中的下一列。
我创建了一个新的Power BI报告,其中包括一个包含Awards表中三列的表:Bid、Awared和Prime。该表的输出如图16-2所示,显示了我正在跟踪的各种状态,从进行中到否,从挂起到是。要决定列的汇总方式,请转到“字段”窗格并选择“投标”字段。您可以看到,窗格现在显示Bid字段数据将被汇总,如图16-3所示。现在,数据可以用其他方式制成表格,但它可能不会为表格的读者提供最佳响应。
使用DAX函数的数字列提供了一系列广泛的聚合函数。您可以通过编程方式或使用下拉菜单对其进行编程。最常用的数字列选项包括:
● Sum
● Average
● Minimum
● Maximum
● Count (distinct)
● Count
● Standard deviation
● Variance
● Median
当您尝试格式化DAX计算时,您会发现一个包含单词的短语“distinct”。然后可能会有另一个看起来几乎一模一样的选择。到底有什么区别?以Count与Count Distinct为例。Count Distinct选项仅显示给定值的唯一实例,而Count显示所有记录的结果。
不要以为数字数据无法汇总。它可以!默认情况下,唯一的区别是字段中的非数字列旁边没有西格玛符号(∑)。文本列将改为汇总。以下是示例类型:
● First (alphabetical)
● Last (alphabetical)
● Count (Distinct)
● Count
还有一些数据和布尔列可能允许聚合。但是,这些列将根据具体情况使用。
您可能会认为,显式度量对Power BI更好,因为它们是计算驱动的--
时期但事实是,隐性措施更容易学习和使用。它们提供了更大的灵活性,因为报告作者可以使用隐式度量快速可视化数据。在创建计算时,显式度量需要付出更多的努力。
当然,每一个积极因素都有消极因素。如果报告作者愿意,隐式度量允许他们创建草率的报告设计。这意味着聚合可能以错误的方式进行。基于代表性列,聚合的数据可能不正确或不合适。在图16-4中,您可以看到这个场景的一个示例。差异与任何投标金额的实际值都不成比例。事实上,如果您仔细查看前面的表,如图16-2所示,请注意,总投标池仅不足160万美元。方差远远超过这个值。
您可以编写任何DAX公式,将度量值添加到模型中的任何表中。唯一的约束是度量值公式必须返回标量或单个值。
度量值不在数据模型中存储值。相反,在查询时使用度量来返回模型数据的摘要实例。此外,度量值不能直接引用表或列。这就是为什么必须使用函数将它们传递到表或列以生成摘要的原因。
度量的复杂性可以归结为聚合了多少列。一个简单的度量可以聚合单个列的值。它会自动执行隐含的度量。在图16-5所示的示例中,您向Awards表中添加了一个度量。方法如下:
请尽快更改格式。在这种情况下,您可以将数字格式更改为货币,并将小数位置设置为2。这有助于创造一致的价值观。
该措施现在通过将格式类型更改为货币和小数点后两位来正确构建财务数据。现在,无论何时添加像Awards这样的面向财务的数据,都会遵循相同的结构。为了证明这一说法,我创建了一个新的度量标准,TypicalBid:
TypicalBid = AVERAGE(Awards[Bid])
一旦将新公式TypicalBid输入Power BI Desktop,就可以根据上下文识别该公式。发生的变化包括切换到货币格式,因为表为“奖励”,列为“投标”。您可以看到修改后的格式类型(货币)的结果,如图16-5所示,这一点很重要,因为Power BI会自动识别更改。
如果公式化方程式中涉及多个度量,例如Profit = Bid- Earned,它被称为一种复合度量。
在这一点上,您已经使用了计算列和度量值。那么,您应该选择哪个,在哪个用例下?
然而,不同之处在于它们的用途、评估和储存标准。表16-2探讨了差异
计算列 | 度量 | |
---|---|---|
目的 | 用新列扩展表 | 汇总数据模型 |
评估点 | 数据刷新时的行上下文 | 在查询时筛选上下文 |
存储 | 存储每行的值 | 从不存储值 |
可视化 | 过滤、分组和排序数据 | 专为摘要而设计 |
DAX表达式分析用于Power BI报告的关键数据。因此,这些表达式必须使用特定的语法和上下文。DAX表达式接受表和列作为引用。请记住以下几点:
如果你看下面的公式,你可以看到从数据表中得到的方程有一个特定的结构:
Profit = SUM(Sales([Earned])
这个方程式有以下语法元素:
在编写方程和公式时,一定要遵守符合这些原则的严格语法。
Power BI将DAX的使用扩展到了其他Microsoft应用程序之外,这是有充分理由的!
使用DAX,您可视化和扩充数据的能力将成倍提高。本章,连同第14章和第15章,将带您了解语法、上下文和函数的基本知识。然而,在一天结束时,你需要首先专注于优化,因为你不希望代码变得笨拙。
DAX有很多可能的功能:知道从哪里开始可能会变得很有挑战性。毫无疑问,要记住我在第15章中讨论的250多个函数是很困难的。但是,您应该熟悉可供使用的15种类型的函数是如何分组的,并能够按类别类型对度量进行排序。如果你想让你的公式没有bug,你也应该意识到要避免的事情。接下来的几节提供了一些提示。
无论何时编写DAX表达式,都有可能编写错误。这是不可避免的。考虑这两种DAX功能来减少疏忽:
ISERROR和IFERROR的表达肯定是有益的,因为它们可以为编写易于理解的表达做出巨大贡献。缺点是:它们会迅速降低计算性能。之所以会发生这种情况,是因为函数同时增加了对系统的命中次数。其中许多错误是由意外的BLANKs或零值引起的,因此了解通过系统处理的数据类型转换错误至关重要。
尽管您可能倾向于使用ISERROR和IFERROR函数,但在开发模型和编写表达式时,通常最好使用防御策略。考虑以下内容:
你可能会时不时地把东西留空,因为这个表达根本没有价值。在这些情况下,如果你发现一个值为零,你应该在放弃之前重新思考。考虑以下度量值,该度量值显式地将BLANK结果转换为0:
Bid (No Blank) =
If (
ISBLANK ([Bid]),
0,
[Bid]
)
以下是另一个将BLANK结果转换为零的度量:
Commissions =
DIVIDE([Commissions], [Sales], 0)
首先,DIVIDE函数获取Commissions,并通过Sales度量进行度量。如果结果为零或为BLANK,则返回第三个参数——换句话说,是备用结果。在本例中,由于0作为替代结果传递,因此保证度量值始终返回一个值。正如您所看到的,这两种度量设计都是低效的,并导致糟糕的报告设计。
Power BI尝试检索筛选器上下文中的所有分组,即使这些项已添加到报表可视化中。问题是,结果是一个重要的查询,导致报告速度缓慢。每一个示例措施都有效地将稀疏的计算转化为戏剧化的制作,导致Power BI因平凡的任务成为内存占用者而停滞不前。坦率地说,这些分组让报告用户不知所措。
这就是为什么您希望高效地使用过滤器上下文、分组和变量。提供更高效率和适当使用变量的示例公式包括以下行:
Commission Payable = DIVIDE ([Commissions], [Sales])
在某些情况下,必须配置可视化以显示所有分组。这意味着您应该通过启用“显示没有数据的项目”选项,在筛选器上下文中返回值或BLANK。
对于DAX,只有一个条件允许返回BLANK。这种情况是指由于无法返回任何有意义的值而强制度量返回BLANK。这是一种高效的方法,使Power BI能够更快地生成报告。
从前,你在学校里学过基本的数学公式。还记得分子和分母之间的区别吗?有了DAX,它更具技术性。您需要知道函数DIVIDE和运算符DIVIDE的用法之间的区别。
使用DIVIDE函数时,您可以传递分子和分母表达式来获得结果。您还可以传入一个值,该值将获得另一个结果:
DIVIDE(, [,])
DIVIDE函数是为了处理除以零而故意创建的。如果没有传入替换项,并且分母为零或为BLANK,则函数应返回一个BLANK。第二个用例是当一个替代结果被传递时——它被返回而不是BLANK。
参考第15章中讨论的IF、ISBLANK或BLANK函数,这些函数并不独立。您至少需要四个DAX函数才能正确完成该函数。这样的编码要求是非常低效的。下面是一个低效(错误)的代码示例:
Bid Margin =
IF (
OR (
ISBLANK([Bids]),
[Bids] == 0
),
BLANK (),
[Bids] / [Sales]
)
此代码效率低下的原因是[Sales]是分母。使用分子[Bindes]将导致无限结果为空白。正如您所知,代码的格式不正确,导致了不必要的错误。
下面是一个使用DIVIDE的例子,它提供了一种更有效的方法来生成完全相同的公式:
Bid Margin =
DIVIDE([Bids], [Sales])
根据你对这两个方程的复习,你应该能够遵循这些规则:
几个带有DAX的字母就说明了一切。您可能需要编写一个DAX表达式,用于测试是否可以使用特定值筛选列。多年来,DAX一直使用特定的值,包括IF、HASONEVALUE和values。例如,如果您需要为加利福尼亚州的客户确定销售税,您可以决定使用以下代码:
CA State Tax =
IF (
HASONEVALUE (Customer [State Tax]),
IF (
VALUES (Customer [State Tax]) = "California",
[Sales] * 0.0725
)
)
如本文所示,只有当STATE TAX列的单个值在当前筛选器上下文中可见时,HASONEVALUE函数才会返回TRUE条件。如果为TRUE,则必须将VALUES函数与特定文本“California”进行比较。如果该文本条件为TRUE,则销售额将乘以0.0725,即7.25%,即加利福尼亚州的州销售所得税。如果HASONEVALUE函数返回FALSE(可能是因为存在多个值筛选列),则第一个If函数返回一个BLANK。
按照这里的结构使用这种技术完全是防御性的,而且很棘手。之所以需要它,是因为它可以为State Tax列生成多个值过滤器。VALUES函数可以返回一个生成多行表的表。也就是说,当你将一个由多行组成的表与一个比例值进行比较时,结果会产生显著的错误。
与其使用三重函数,为什么不只使用一个过滤器,即SELECTEDVALUE函数呢?
有时,简洁、优雅和高效确实赢得了比赛。使用一个函数对三个函数的相同代码方程可以这样写:
CA Sales Tax =
IF (
SELECTEDVALUE (Customer [State Tax]) = "California",
[Sales] * 0.0725
)
它确实干净、简单、漂亮!
您可能需要编写DAX表达式,以便每隔一段时间对表行进行计数。有几种方法可以实现这一点。您的第一个选择是使用COUNT函数对列值进行计数。另一种选择是使用COUNTOWS函数对表行进行计数。两种选择都能得到相同的结果。有一点需要注意:只要计数的列没有BLANKs,两者都可以。
在第一个用例中:
Bids Processed =
COUNT(Bids[BidDate])
Bid表中显示的粒度是每投标一行,BidDate列没有空白。度量值返回正确的结果集。
Bids Processed =
COUNTROWS(Bids)
同样,效率和优雅赢得比赛的原因多种多样。其次,它不考虑任何表列中的BLANKs。专栏的意图是明确的,因为它的功能是自我描述的。
每当您查看Power BI中的一对表时,您都可以找到许多关系。你可能有很多不活跃的关系。但是,使用DAX一次只能评估一个活动关系。
默认情况下,DAX代码使用活动关系。当与USERELATIONSHIP函数关联时,DAX可以使用特定的非活动关系。
在第14章中,我简要介绍一下上下文。让我们再次重申上下文的重要性,因为它确实很重要。使用DAX,您将完成动态分析。这就是为什么必须始终考虑上下文——可用于执行计算的数据。您有以下两种选择:
在本章的前面,我将讨论度量和列之间的差异。但这是上帝诚实的事实——在Power BI中,度量总是能产生更好的DAX结果。为什么?因为度量就像一个虚拟计算,它存在于你的模型之上。度量只有在需要使用时才会执行,而计算列则大量集成到模型中。
以下是对计算列使用度量值的其他一些原因:
假设您打算执行需要复杂计算的嵌套计算。在这种情况下,度量分支会剪切掉大量代码,从而提高计算性能。计算列不会提高计算性能。
度量值组保持报告的整洁和有序,帮助您快速、高效地查找数据。
如果有什么应该在本章结束时无数次重申的话,那就是结构很重要。如果您的代码中不需要某些内容,请将其删除。如果内部列正在使用中,请隐藏它,而不是在Power BI中公开它,这样就不需要使用DAX公开它。
如果您想使用DAX作为变量来调用列,请重命名它,这样它才有意义,因为所有名称都应该是用户友好的。而且,只要可能,就要使用明确的度量,因为您将感谢代码的可读性和加速的性能。