【DAX学习】2、理解计算列和度量值

image.png

1、DAX基础语法

DAX公式一般的格式是将表名用单引号括起来,后跟用方括号括起的列名,如下:

'Sales'[Quantity]

但是标准是在列引用中始终使用表名,在度量引用中始终避免使用表名。
在以后介绍了上下文转换之后,我们会了解到这个标准背后的基本原理

Sales[Quantity] * 2  -- 这是计算列的写法
[Sales Amount] * 2   -- 这是度量值的写法
'--'和'//'在DAX中表示单行注释
多行注释以'/*'开始,以'*/'结束。

1.1 DAX数据类型
DAX支持七种数据类型参与计算

image.png

DAX会在操作符需要时自动将字符串转换为数字,并将数字转换为字符串。
例如,如果我们使用连接字符串的&操作符,DAX将其参数转换为字符串。
下面的公式以字符串形式返回“54”:

= 5 & 4

另一方面,该公式返回一个值为9的整数结果:

= "5" + "4"

但是上述方式并不推荐,如果真想转换数据类型,推荐显式转换,上面的例子可以改为:

= VALUE ( "5" ) + VALUE ( "4" )

1.2 DAX操作符

image.png

1.3 构造表
在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操作符一起使用。例如,:

'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函数编写条件表达式。例如:

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

IF函数有三个参数,但只有前两个是必需的。第三个选项是可选的,默认为空白。所以以下两种写法都是一样的

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

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

2、计算列和度量值的区别

2.1 计算列

计算列是添加到模型中的新列,但它不是从数据源加载的,而是通过使用DAX公式创建的。
计算列和表格中的其他列一样,还可以使用计算列来定义关系。
定义计算列的DAX表达式在计算列所属表的当前行上下文中操作。对列的任何引用都将返回该列的当前行值,我们不能直接访问其他行的值。所有计算的列都占用内存,并且都是在表处理期间计算的。

在创建复杂的计算列时,存放在内存非常有用。计算复杂计算列所需的时间始终是处理时间而不是查询时间,这样可以获得更好的用户体验。不过,要注意计算列使用了宝贵的RAM。
例如,如果我们有一个复杂的计算列公式,我们可能会试图将计算步骤拆分到不同的中间列中。尽管这种方式在项目开发期间很有用,但在生产中却是一个坏习惯,因为每个中间计算都存储在RAM中,浪费了宝贵的空间。
如果模型是基于DirectQuery的,那么行为就会有很大的不同。在DirectQuery模式下,当表格引擎查询数据源时,计算的列是动态计算的。这可能导致数据源执行大量查询,从而产生速度较慢的模型。

例如,我们可以利用下单时间和交货日期两列数据,两列相减得出出交付订单所需的天数,以下是计算列的公式:

Sales[DaysToDeliver] = INT ( Sales[Delivery Date] - Sales[Order Date] )

2.2 度量值
度量值是用聚合函数计算出来的值,它的结果只有一个,而计算列得出的结果是一列的值
例如,在Sales表中定义一些计算列来计算毛利率金额:

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

如果想显示毛利占销售额的百分比,可以使用以下公式创建一个计算列:

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

这个公式在行级别上计算正确的值,如下图所示,但是在总体总数级别上,结果显然是错误的。

image.png

可以看出来,551.46%是所有毛利占比的总和,这种计算方式显然是错误的,我们应该以所有毛利的总和除以所有销售额的总和
如果需要对聚合值进行操作,而不是逐行操作,则必须创建度量。我们使用:=来定义度量值,而不是等号=,以便在代码中更容易区分度量和计算列。
定义GrossMarginPct作为度量值后,结果是正确的,如下图所示。

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

度量值和计算列都使用DAX表达式,不同之处在于计算的环境

计算列的值是在数据刷新期间计算的,它使用当前行作为上下文。结果不依赖于用户在报表上的操作。

度量值对当前上下文定义的数据聚合进行操作。例如,在透视表中,根据透视表的行过滤源表,并使用这些过滤器聚合和计算数据。换句话说,度量值总是在计算环境下对数据的聚合进行操作(关于计算上下文会在之后进一步说明)。

因此,当在度量值中使用SUM(Sales[SalesAmount])时,我们指的是筛选聚合的所有行的总和。但是,当我们在计算列中使用Sales[SalesAmount]时,我们指的是当前行中SalesAmount列的值。

需要在表中定义度量值,但是并不真正属于表格。实际上,我们可以将度量值从一个表移动到另一个表,而不会丢失其功能。

因为度量值在查询时计算,它不会消耗内存和磁盘空间。通常,当我们可以用两种方式表达计算时,度量值是首选。应该将计算列的使用限制在少数严格需要它们的情况下。具有Excel经验的用户通常更喜欢计算列而不是度量,因为计算列非常类似于在Excel中计算的方式。然而,在DAX中计算值的最好方法是通过度量值。

此系列是对The_Definitive_Guide_to_DAX第2版的学习笔记

欢迎关注微信公众号:纸上躬行君

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