【DAX圣经】第三章:使用基本表函数(2)

理解 ALL, ALLEXCEPT, and ALLNOBLANKROW

ALL 都是一个有用的函数,它返回一个表的所有行或一个列的所有值,这取决于您所使用的参数。例如,下面的DAX查询返回产品表中的所有行

EVALUATE
ALL ( Product )

你不能在 ALL 参数中指定一个表表达式。您必须指定表名或列名列表。如果您使用单个列,那么结果就是一张原表去重后形成的唯一值列表,如图3-8所示。

EVALUATE 
ALL ( Product[Class] )
图3-8 对列的所有值的查询返回一个所有惟一值的列表

你可以在 ALL函数的参数中指定来自同一个表的更多列。如果您使用许多列,那么结果将是一张包含了这些列中已有的值组合的列表(可以理解为对多个列做笛卡尔积,然后筛选其中原表中已经存在的列组合)。例如,下面的表达式产生如图3-9所示的结果:

EVALUATE 
ALL ( Product[Class], Product[Color] ) 
ORDER BY Product[Color]
图3-9 关于更多列的all函数查询返回一个现有的值组合的列表

在所有的变体中,ALL函数忽略了任何现有的过滤器来产生它的结果。您可以将ALL函数用作迭代函数的参数,例如SUMX和FILTER,或者作为CALCULATE函数中的筛选参数(稍后您将看到)

如果您想要在一个ALL函数调用中包含表格的大部分列,您可以使用ALLEXCEPT函数来代替。ALLEXCEPT函数的语法需要一个表,后面是您想要从结果中排除的列。因此,在表格的其他列中,ALLEXCEPT返回一张表,其中包含了其他列现有的值组合的唯一列表。

在实际运用中,这是一种编写DAX表达式的方法,它将自动包含非参数列的所有结果,以及在之后的表模型中可能出现的任何额外的列。例如,如果您有一个包含5个列(ProductKey, Product Name, Brand, Class, Color)的产品表,那么下面的语法就会产生相同的结果

ALL ( Product[Product Name], Product[Brand], Product[Class] ) 

ALLEXCEPT ( Product, Product[ProductKey], Product[Color] )

但是,如果您稍后添加两列 Product[Unit Cost]和Product[Unit Price],那么ALL函数的结果会忽略它们,而ALLEXCEPT函数则将返回等效的:

ALL ( 

Product[Product Name], 

Product[Brand], 

Product[Class],

Product[Unit Cost], 

Product[Unit Price]

 )

下列查询返回一个表,该表除了产品表之外的Product Code和Color以外的所有列。图3-10的结果与原始表的行数相同,因为结果包括ProductKey列,它每一行具有惟一的值。结果中的其他列组合可能会返回较少的行数,因为ALLEXCEPT消除了返回列中值的重复组合。

EVALUATE 

ALLEXCEPT ( Product, Product[ProductKey], Product[Color] )
图3-10 ALLEXCEPT返回现有的所有非参数指定列的值的组合

在前面的例子中,您已经在一个EVALUATE语句中看到了ALL函数,它执行DAX表达式,而没有任何现有的筛选条件。出于这个原因,最好是看一个在透视表中使用ALL函数计算表的行数的例子,这些例子中每个单元格使用不同的筛选条件来计算度量值。考虑以下度量值:

[Products] := COUNTROWS ( Product ) 

[All Products] := COUNTROWS ( ALL ( Product ) ) 

[All Brands] := COUNTROWS ( ALL ( Product[Brand] ) )

您可以在图3-11中看到每个度量值的不同结果的示例

图3-11所有产品和所有品牌都忽略了行上的类别并且总是显示相同的数字

对于每一个产品类别,在All Products和All Colors列中,总是有相同的结果。在ALL函数的计算中忽略了透视表中单元格的筛选条件。

当你调用ALL函数在一个关系的父表时,如果子表包含一个或多个行在父表中不匹配任何值的行,就会返回一个额外的空白行。您可以通过使用 ALLNOBLANKROW 函数 代替ALL函数来忽略这个特殊的行。

考虑下面的度量值:

[All Products] := COUNTROWS ( ALL ( Product ) ) 

[All NoBlank Products] := COUNTROWS ( ALLNOBLANKROW ( Product ) )

[All Brands] := COUNTROWS ( ALL ( Product[Brand] ) )

[All NoBlank Brands] := COUNTROWS ( ALLNOBLANKROW ( Product[Brand] ) ) 

[All Sizes] := COUNTROWS ( ALL ( Product[Size] ) ) 

[All NoBlank Sizes] := COUNTROWS ( ALLNOBLANKROW ( Product[Size] ) )

在图3-12中,您可以看到ALL和ALLNOBLANKROW度量值之间的区别。对于Product表 和 the Products[Model]列,ALL版本的度量值比ALLNOBLANKROW版本多返回一行。原因是销售表中有一些行,在产品表中没有与之匹配的行,因此额外的一行实际上被添加到产品表中,您可以在图3-12中看到(空白)行中的结果。

图3-12 如果目标表包含一个因为不匹配而产生额外的空白行,那么ALL和 ALLNoBlank度量值都是不同的

您应该注意到, All Sizes和All NoBlank Sizes计算结果总是相同。这些度量查询Products[Size]列的数量。在这种情况下,ALL和ALLNOBLANKROW函数返回相同的值,因为 Products[Size]列已经包含了一个产品的空白值。在图3-13的例子中,有569个空白大小的产品,加上一个额外的无法引用销售表产品空白产品,总共有570个。对于Products[Size]列,所有这些行都被分组在同一个的(空白)值中。

图3-13 透视表的行是每个产品名称的SIZE。第一个(空白)值的大小包括空白SIZE的产品和没有在销售表中匹配到的额外空白产品

只有当你写了一个DAX公式需要它忽略了关系中不匹配的值时,你才应该使用ALLNOBLANKROW。然而,相较于ALL函数,ALL的使用则显得更为通用,而ALLNOBLANKROW用的则很少。

理解 VALUES和 DISTINCT

在上一节中,您已经看到,ALL主要用于返回一个列中所有惟一值的表。DAX提供了另外两个类似的函数,它们返回一个列的惟一值列表:VALUES和DISTINCT

如果在没有任何其他筛选条件情况下,在EVALUATE语句中 VALUES和 DISTINCT似乎是相同的。然而,当你把这些函数放在DAX度量值中时,你可以观察到一个不同的行为,因为计算发生在一个透视表的每个单元格的不同上下文中。考虑以下在产品表中Brand列和 Size 列计算不同唯一值数量的度量值。

[Products] := COUNTROWS ( Product ) 

[Values Brands] := COUNTROWS ( VALUES ( Product[Brand] ) ) 

[Distinct Brands] := COUNTROWS ( DISTINCT ( Product[Brand] ) )

[Values Sizes] := COUNTROWS ( VALUES ( Product[Size] ) )

[Distinct Sizes] := COUNTROWS ( DISTINCT ( Product[Size] ) )

VALUES 返回当前可见单元中惟一值列表,包括没有匹配的空白行。 DISTINCT同样,但是不返回没有匹配的空白行。但是,如果一个空白值作为列的有效值出现,那么这两个函数都将包含一个空行。唯一的区别是添加了空白行来处理关系中缺失值

一个例子可能会帮助你区分这种不同。正如表3-14,每个产品等级筛选出不同数量的产品。比如Deluxe有360种产品,有11个不同的品牌和204个不同的尺码。 VALUES 和 DISTINCT 返回相同的结果,只有一个例外:透视表中行的(空白)产品类。结果增加了一个虚拟行,以显示在Sales Amount中没有匹配到的产品。

图3-14 VALUES 和 DISTINCT 的区别,只有当一个空白产品被添加到报告的(空白)行中是可见的模型中以包含不匹配的行

另一个在图3-14中可见的区别在 Grand Total中。 VALUES 应用于 Product[Brand],返回的值比应用在同样列上DISTINCT的值多一个。然而,这并不会发生在 VALUES 应用于Products[Size]的值上,后者返回的值与 DISTINCT应用在同样的列上相同。这个原因是 Distinct Sizes 列包含至少一个产品的空白值,因此添加的空白产品不会为 Distinct Sizes 列添加一个新的惟一值。

当没有筛选条件时, DISTINCT行为与ALLNOBLANKROW的行为相同,与此对比,VALUES行为与ALL行为相同。

VALUES也接受一张表作为参数。在这种情况下,它返回在当前可见的整个表,同时也包括没有匹配的空白行。例如,在数据模型中考虑以下度量值,其中Sales表与 Product 表有关系,并包含与产品主键不匹配的交易。

[Products] := COUNTROWS ( Product )

[Values Products] := COUNTROWS ( VALUES ( Product ) )

[All NoBlank Products] := COUNTROWS ( ALLNOBLANKROW ( Product ) )

[All Products] := COUNTROWS ( ALL ( Product ) )

VALUES作为标量值使用

即使 VALUES 是一个表函数,您也经常使用它来计算标量值,因为在DAX中有一个特殊的特性,您将在本节中学习。例如,您可以在表达式中找到VALUES,比如下面的表达式,它会显示颜色名称,以确保某一特定选择的产品都具有相同的颜色:

[Color Name] :=
IF ( COUNTROWS ( VALUES ( Product[Color] ) ) = 1, VALUES ( Product[Color] ) )

您可以在图3-15中看到结果。当Color Name列包含空白时,这意味着有两种或更多不同的颜色

图3-15当VALUES返回一行时,您可以将其用作标量值,例如Color Name 度量值

这里的有趣之处在于,我们将VALUES的结果作为标量值,即使它返回一个表。这不是一种VALUES特殊的行为而是DAX语言一种更普遍的行为。

如果一个表表达式返回一个带有一行和一列的表,那么如果需要的话,可以自动转换成为标量值。

在实践中,如果结果恰好有一行和一列,您可能会使用任何表表达式作为标量值。当表格返回更多的行时,您会在执行时得到这个错误:“在期望单个值的地方提供了多个值的表。“出于这个原因,您应该始终编写一个返回不同结果的条件来确保能够转换为标量值,以防表表达式返回更多的行(您应该已经知道,当您编写DAX表达式时,表表达式是否只返回一行)。

前面例子的 Color Name度量使用COUNTROWS来检查产品表的 Color 列是否只有一个值。一种更简单的方法是使用HASONEVALUE,它执行相同的检查,如果列只有一个值返回的值,反之则返回 FALSE 。以下两个语法是等价的

COUNTROWS ( VALUES ( <column> ) ) = 1

HASONEVALUE ( <column> )

您应该使用HASONEVALUE而不是COUNTROWS,原因有两个:它更易于阅读,而且可能会稍微快一些。下面是基于HASONEVALUE的 Color Name 度量值的更好的实现:

[Color Name] :=
IF ( HASONEVALUE ( Product[Color] ), VALUES ( Product[Color] ) )

您经常使用 VALUES 作为标量表达式的原因是它返回单个列,并且可能返回单行,这取决于执行上下文。在许多DAX模式中, VALUES 作为标量表达式是很常见的,并且在本书中反复出现。

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

推荐阅读更多精彩内容