2.2了解计算列和度量值

第2章 DAX简介

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

了解计算列和度量值

现在您已经了解DAX语法的基础知识,您需要学习DAX中最重要的概念之一:计算列和度量值之间的区别。尽管乍看之下计算列和度量值可能看起来很相似,因为您可以使用其中任何一种来进行某些计算,但实际上它们是不同的。了解两者的差异是释放DAX功能的关键。

计算列

根据所使用的工具,可以不同的方式创建计算列,其实质是一样的:计算列是添加到模型中的新列,但是它不是通过数据源加载的,而是通过DAX公式创建的。

计算列与表格中的任何其他列一样,可以在矩阵或其他报表的行、列引用和筛选。如果需要,还可以使用计算列来定义关系。为计算列定义的DAX表达式在计算列所属表的当前行的上下文中运行。对所属表列的引用都会返回当前行该列的值。无法直接访问其他行的值。

如果使用Tabular的默认导入模式,而不使用DirectQuery,要记住有关计算列的一个重要概念是在数据库处理期间计算这些列,然后将其存储在模型中。如果您习惯于使用SQL计算列(非持久性),则该概念看起来颇为奇怪,这些列是在查询时计算的,并且不使用内存。但是,在Tabular(表格模型)中,所有计算的列都占用内存空间,并在表处理期间进行计算。

每当我们创建复杂的计算列时,此行为很有用,能带来更好的用户体验,因为计算复杂的计算列耗时始终是处理时间而不是查询时间。但是,请注意,计算列会使用宝贵的内存。例如,如果计算列具有复杂的公式,则可能会通过中间辅助列来分步计算,尽管此技术在项目开发中很凑效,但在运行中却是个坏习惯,因为每个中间计算都存储在内存中,浪费了宝贵的内存空间。

如果模型是基于DirectQuery的,则行为会大不相同。在DirectQuery模式下,当表格模型引擎查询数据源时,将即时计算计算列。这可能会导致数据源执行繁重的查询,从而导致模型变慢。

计算订单的交货时间
假设有一个Sales表包含有Order DateDelivery Date列。使用这两列,可以计算出交付订单所涉及的天数。由于日期存储为1899年12月30日之后的天数,因此简单的减法即可计算两个日期之间的天数差:
Sales[DaysToDeliver] = Sales[Delivery Date] - Sales[Order Date]
但是,因为用于减法中的两列都是是日期,所以结果也是日期。要产生数值结果,请按以下方式将结果转换为整数:
Sales[DaysToDeliver] = INT ( Sales[Delivery Date] - Sales[Order Date] )

结果如图2-2所示

图2-2 两个日期相减并将结果转换为整数计算出两个日期之间的天数

度量值

计算列很有用,但是可以用另一种方式在DAX模型中定义计算。当不想为每一行计算值,而是希望聚合表中多行的值时,您会发现被称为度量值的计算很有用。

例如,您可以在Sales表中定义几个计算列来计算毛利:

Sales[SalesAmount] = Sales[Quantity] * Sales[Net Price]
Sales[TotalCost] = Sales[Quantity] * Sales[Unit Cost]
Sales[GrossMargin] = Sales[SalesAmount] – Sales[TotalCost]

如果您想将毛利显示为销售额的百分比怎么办?您可以使用以下公式创建一个计算列:

Sales[GrossMarginPct] = Sales[GrossMargin] /
Sales[SalesAmount]

如图2-3所示:该公式在行级别计算正确的值,但是在总计级别,结果显然是错误的。

图2-3 GrossMarginPct列显示每行的值正确,但总计不正确

总计级别显示的值是计算列中逐行计算的各个百分比的总和。当计算一个百分比的合计值时,不能依赖于计算出的列,相反,需要根据各个列的总和来计算百分比。必须将总计值计算为毛利的总和除以销售额的总和。在这种情况下,我们需要计算聚合比率;你不能使用计算列的总计。换句话说,要计算总和的比率,而不是比率的总和。

简单地将GrossMarginPct 列的总计更改为平均值作为结果,同样是错误的,因为这样做会对百分比进行错误评估,而没有考虑金额之间的差异。该平均的值的计算结果见图2- 4,可以很容易地检查(330.31 / 732.23)不等于显示值45.96%, 而应该是45.11%。

图2-4将聚合方法更改为 AVERAGE不能提供正确的结果

GrossMarginPct的正确计算应用度量值来实现:

 GrossMarginPct:= SUM (Sales[GrossMargin])/SUM
 (Sales[SalesAmount])

如前所述,使用计算列无法获得正确的结果时,如果您需要对聚合值进行操作,而不是逐行进行操作,则必须创建度量值。您可能已经注意到我们使用了:=定义度量值而不是等号(=)。这是我们在整本书中使用的标准,可以更加容易区分代码中的度量值和计算列。

在将GrossMarginPct定义为度量之后,结果是正确的,如图2-5所示。

图2-5 度量值GrossMarginPct 显示正确的总计

度量值和计算列均使用DAX表达式;区别在于评估的背景。度量值是在视觉元素的上下文或DAX查询上下文中评估的;计算列的计算是在其所属表的行级别进行的。视觉元素的上下文(在本书的后面,您将学到这是一个筛选上下文)取决于报表中用户的选择或DAX查询的格式。因此,在度量值中使用SUM(Sales [SalesAmount])时,是指在视觉元素的上下文聚合的所有行的总和。但是,当我们在计算列中使用Sales [SalesAmount]时,是指当前行中SalesAmount列的值。

需要在表中定义度量值。这是DAX语言的要求之一。但是,该度量值并不真正属于该表。实际上,我们可以将度量从一个表移动到另一表,而不会失去其功能。

计算列和度量值之间的差异
尽管它们看起来很相似,但计算列和度量值之间还是有很大的差异。计算列的值是在数据刷新期间计算的,并且它使用当前行作为上下文。结果不取决于报告上的用户活动。度量值对当前上下文定义的数据聚合进行操作。例如,在矩阵或数据透视表中,根据单元格的坐标,对源表进行筛选并使用这些筛选聚合和计算数据。换句话说,度量值始终在评估上下文背景下对数据聚合进行操作。评估上下文将在第4 章 “ 了解评估上下文 ”中进一步解释。

既然已经了解了计算列和度量值之间的差异,那么讨论何时何时用计算列何时用度量值变得很有意义。有时两者都是选项之一,大多数情况下,计算需求决定了选择。

作为开发人员,无论何时要执行以下操作,都必须定义一个计算列:

  • 将计算结果放在切片器中,或在矩阵、数据透视表的行或列中查看结果(与"值"区域相对),或者在DAX查询中将计算列用作筛选条件。
  • 定义一个严格绑定到当前行的表达式。例如,Price * Quantity,对这两列的平均值或总和不起作用。
  • 分类文字或数字。例如,量值的范围,客户年龄范围,例如0-18、18-25等。这些分类通常用于筛选或切片器。

但是,要显示计算值反馈用户的选择或在报告中作为聚合值呈现时,必须定义度量值:

  • 计算报表中的利润百分比
  • 按年份和地区筛选时计算某产品与所有产品的比率

我们既可以用计算列又可以用度量值来定义许多计算,尽管需要分别使用不同的DAX表达式。例如,可以将GrossMargin定义为计算列:
Sales[GrossMargin] = Sales[SalesAmount] - Sales[TotalProductCost]

但是,也可以将其定义为度量:
GrossMargin := SUM ( Sales[SalesAmount] ) - SUM ( Sales[TotalProductCost] )

这种情况下建议使用度量值,因为在查询时对其进行评估不会消耗内存和磁盘空间。通常,只要您可以同时使用两种方法来计算,则首选度量值。您应该将计算列的使用严格限制在需要它们的少数情况。具有Excel经验的用户通常更喜欢使用计算列而不是度量值,因为计算列与Excel中计算的方式非常相似。
但是,在DAX中计算值的最佳方法是通过度量值。

在计算列中使用度量值
显而易见,一个度量值可以引用一个或多个计算列。尽管不那么明显,但反之亦然,计算列也可以引用度量值。这样,计算列将强制在当前行定义的上下文计算度量值。此操作将度量值的结果转换并固定到列中,该列将不受用户操作的影响。显然,这样的操作只有在某些特殊情况下才有意义,因为度量值的计算通常很大程度上取决于用户在视觉对象中所做的选择。而且,作为开发人员在计算列中使用度量时,依赖于称为上下文转换的功能,这是DAX中的一种高级计算技术。强烈建议在计算列中使用度量之前,阅读并理解第4章,其中详细介绍了评估上下文和上下文转换。

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

推荐阅读更多精彩内容

  • 到本书的这一章时,您已经学习了DAX语言的基础知识。您知道如何创建计算列和度量值,并且您已经很好地理解了DAX中的...
    daxbi阅读 6,627评论 4 28
  • 在快速介绍前一章之后,现在是时候开始讨论DAX语言了。在这一章中,您将学习语言的语法、计算列和度量值(在Excel...
    daxbi阅读 3,652评论 0 11
  • 在本章中,您将学习DAX中标量函数和表函数之间的区别。表函数对于DAX中的内部计算非常重要,当您为度量值或计算列编...
    BI_Jay阅读 4,249评论 0 7
  • 你站在我旁边,像一只小蚂蚁。 小蚂蚁意识到,这庞大的躯体是什么。 不一样的沟通方式,彼此都感觉对方的存在。 我站在...
    素兴心地阅读 433评论 1 1
  • (文章是本人原创作品,未经授权,禁止任何形式的转载) “碧玉妆成一树高, 万条垂下绿丝绦。 ...
    明月清风sxw阅读 1,129评论 13 31