[知识体系] 理解 VALUES

  [复制链接]
查看107808 | 回复119 | 2021-2-21 19:02:07 | 显示全部楼层 |阅读模式
VALUES 是 DAX 最常用的表函数之一
语法结构
  1. VALUES ( <TableName Or ColumnName> )
复制代码

VALUES 是一个表函数,可以用列名或表名作为参数,VALUES 返回参数在当前筛选上下文中的所有可见值。


  • 当使用列作为参数时,VALUES 返回列的不重复值组成的表
  • 当使用表作为参数时,VALUES 返回的表与源表具有相同的列,并且不删除重复的行
当使用表作为参数时,VALUES 只接受物理表,不接受返回表的表达式。而另一个相似的函数 DISTINCT 可以使用返回表的表达式,并且会删除表中的重复行

在存在筛选上下文的环境(例如数据透视表)中使用 VALUES 函数时,VALUES 返回的惟一值将受到筛选器的影响,如果你要忽略筛选器的影响,可以使用 ALL。例如,下面这个度量值对 CustomerKey 列在当前筛选上下文中可见的非重复值的数量进行计数
  1. [NumOfCustomers] := COUNTROWS ( VALUES ( Sales[CustomerKey] ))
复制代码
理解 VALUES 和 DISTINCT

ALL 函数使用一列作为参数时可以返回唯一值列表,DAX 还提供了另外两个类似的函数用来返回一列的唯一值:VALUES 和 DISTINCT


VALUES 和 DISTINCT 在没有任何其他筛选器的 EVALUATE 语句中,与 ALL 函数的作用看起来相同,但是, 当你将这些函数放在 DAX 度量值中时,可以观察到不同的行为,因为计算发生在数据透视表每个单元格不同的上下文中。请考虑以下度量值:计算品牌列和产品表的唯一值的数量。
  1. [Products]:= COUNTROWS ( Product )
  2. [Values Brands]:= COUNTROWS ( VALUES ( Product[Brand] ) )
  3. [Distinct Brands]:= COUNTROWS ( DISTINCT ( Product[Brand] ) )
  4. [Values Sizes]:= COUNTROWS ( VALUES ( Product[Size] ) )
  5. [Distinct Sizes]:= COUNTROWS ( DISTINCT ( Product[Size] ) )
复制代码

VALUES 返回当前单元格中可见的唯一值列表,其中包含为不匹配值生成的空白行。DISTINCT 也是相同的行为,但不返回空白行。但是,如果空值作为列的有效值出现,那么这两个函数都将包含空白行。所以它们的唯一的区别是是否添加空行以处理由参照完整性产生的关系中的缺失值。


下面的例子可能有助于澄清这种差异,如下图所示,每个产品类别都筛选出不同数量的产品。例如, 有 360 种产品是豪华等级, 其中包含 11 种唯一品牌和 204 种唯一尺寸。VALUES 和 DISTINCT 每行返回相同的数字但有一处例外:透视表行标签上的空白等级。结果中包含的这个虚拟行用来显示未匹配产品的销售额。


7110211936391.jpeg

VALUES 和 DISTINCT 的区别在于是否把空白添加到模型以囊括那些未匹配的行


从总计中可以看到另一个差异。应用于 Product[Brand] 列的 VALUES 函数返回的值不同于同一列的 DISTINCT。但是,这种情况不会发生在 Products[Size] 列上,VALUES 和 DISTINCT 返回相同的值。原因是,尺寸的唯一值里已经包含了空值(至少有一个产品的尺寸是空白的), 因此添加空白产品不会向尺寸列添加新的唯一值。


当没有筛选器时,DISTINCT 的行为对应于 ALLNOBLANKROW,而 VALUES 的行为则对应于 ALL。


VALUES 也接受表作为参数,在这种情况下,它返回当前单元格中可见的整个表,包括由于参照完整性产生的空行。例如,在数据模型中考虑以下度量值,其中销售表与产品表存在关系,并且包含与任何现有产品都不匹配的产品交易记录。
  1. [Products]:= COUNTROWS ( Product )
  2. [Values Products]:= COUNTROWS ( VALUES ( Product ) )
  3. [All NoBlank Products]:= COUNTROWS ( ALLNOBLANKROW ( Product) )
  4. [All Products]:= COUNTROWS ( ALL ( Product ) )
复制代码

在下图所示的这个案例中,你可以看到当没有筛选器时,VALUES 函数和 ALL 函数的不同行为,包括添加的空白行以显示未匹配产品的销售额。[Products]这个度量值在这里统计产品表的行数,忽略可能的空行,与 ALLNOBLANKROW 在总计行的行为相同。


7110211936392.jpeg

VALUES 和 ALL 都在产品表中添加空白行,以显示与销售表不匹配的值
在 Analysis Services 2012/2014 和 Power Pivot for Excel 2013 中,DISTINCT 还没有移除重复行的功能,现在你可以在 Excel 2016 和 Power BI Desktop 中使用这个函数移除重复行。
将 VALUES 函数用作标量值

虽然 VALUES 是一个表函数,你也会经常使用它来返回单值(标量值),本节你将学习 DAX 的这个特性。例如,你可以在如下表达式中找到 VALUES:如果某一筛选条件下的所有产品都有相同的颜色,则显示颜色名称:
  1. [Color Name] :=
  2. IF (
  3.     COUNTROWS (
  4.         VALUES ( Product[Color] )
  5.     ) = 1,
  6.     VALUES ( Product[Color] )
  7. )
复制代码

你可以在下图中看到结果。当 Color Name 列包含空白时,表示有两个或多个不同的颜色。


7110211936393.jpeg

当 VALUES 函数返回单行时可以用作标量值


这里有趣的一点是, 即使返回表, 我们也可以将 VALUES 的结果用作标量值。这不是 VALUES 的特殊行为, 它是 DAX 语言的一种更一般的行为:


如果返回表的表达式结果是包含一行一列的表, 则可以转换为标量值, 这种转换在需要时自动完成。


实际上, 如果结果恰好是一行和一列, 则可以将任何返回表的表达式用作标量值。如果表返回多行, 在执行时会出现此错误: “该表达式引用多列,多列不能转换为标量值”。因此,在表表达式返回多行(在编写 DAX 表达式时,你应该已经知道表表达式是否只返回一行)的情况下,你应该始终使用返回不同结果的条件来保护对标量值的转换。


上一个示例的 Color Name 度量值使用 COUNTROWS 检查产品表的颜色列是否只有一个选中的值。实现相同控制的一种更简单的方法是使用 HASONEVALUE,它执行相同的检查,如果列只有一个值时返回 TRUE,否则返回 FALSE。以下两种语法是等价的:
  1. COUNTROWS ( VALUES ( <column> ) ) = 1
  2. ----------- 等价用法 ----------------
  3. HASONEVALUE ( <column> )
复制代码

你应该使用 HASONEVALUE 而不是 COUNTROWS,原因是它更易于阅读,而且计算的时候可能会稍微快一些。下面是基于 HASONEVALUE 的 Color Name 度量值的推荐写法:
  1. [Color Name] :=
  2. IF (
  3.     HASONEVALUE ( Product[Color] ),
  4.     VALUES ( Product[Color] )
  5. )
复制代码

通常使用 VALUES 作为标量表达式的原因是,它返回单个列,并可能返回单个行,这取决于计值上下文。使用 VALUES 作为标量表达式在许多 DAX 模式中很常见,你会经常遇到。

案例文件下载
点此下载
VALUES 用法总结

VALUES 是 DAX 中使用频率很高的函数,接下来对 VALUES 在实战中的所有用法做一个梳理。

返回唯一值的列表

这一点很像 ALL 函数,VALUES 只返回不同的值。对于一列颜色 {Red, Red, Red, Blue, Red, Red, Red}, VALUES 和 ALL 函数都将返回一个表,该表由一列组成,该列是{Red, Blue}。这两个函数的不同之处在于 VALUES 在筛选上下文中计算,而 ALL 忽略筛选上下文。

将列转换为表

VALUES 的作用之一是将列转换为表。这对于需要调用表的函数非常有用。比如 SUMXFILTERCALCULATECOUNTROWSTOPN,有很多类似的函数需要表作为参数。唯一要注意的是,VALUES 执行的不是从列到表的直接转换,因为只有唯一的值会存在。

引入外部筛选上下文

这也是一种经典用法,ALL 会移除所有筛选器,而使用 VALUES 可以将已经被忽略的特定筛选上下文重新引入。
  1. CALCULATE([Measure], ALL(Calendar), VALUES(Calendar[Year]))
复制代码

尽管 ALL(Calendar)移除了 Calendar 表上的所有筛选器,但 VALUES(Calendar[Year])从初始筛选上下文中恢复了年份列的筛选器。等价于下面的写法:
  1. CALCULATE([Measure], ALLEXCEPT(Calendar, Calendar[Year]))
复制代码
检查正在生效的筛选上下文
  1. =IF (HASONEVALUE(Calendar[Month]),
  2.        IF (VALUES(Calendar[Month]) = "April", "April 被筛选了", "其他月份"),
  3.        "多月份"
  4.   )
复制代码
将列转为标量值



如果在只有一个值的单列上调用 VALUES(或者有多个相同的值),那么它将返回一个可以用作标量的值,上文已经介绍过,这是 DAX 语言的一种特性。
回复

使用道具 举报

棉花糖 | 2021-4-24 15:37:51 | 显示全部楼层
学习下
回复

使用道具 举报

沙王 | 2021-5-13 20:10:14 | 显示全部楼层
秀起来~
回复

使用道具 举报

2110495 | 2021-6-6 17:26:10 | 显示全部楼层
为了三千积分!
回复

使用道具 举报

lovedvd | 2021-8-6 11:35:26 | 显示全部楼层
在撸一遍。。。
回复

使用道具 举报

bateer2002 | 2021-8-21 15:45:56 来自手机 | 显示全部楼层
介是神马?!!
回复

使用道具 举报

claire87 | 2021-10-2 21:23:17 来自手机 | 显示全部楼层
回个帖子,下班咯~
回复

使用道具 举报

简单爱你 | 2021-10-4 09:38:39 | 显示全部楼层
不错不错.,..我一直很喜欢
回复

使用道具 举报

泥公仔 | 2021-10-9 17:13:19 来自手机 | 显示全部楼层
忙完了,来看看视频
回复

使用道具 举报

雄蟹 | 2021-10-16 09:28:27 来自手机 | 显示全部楼层
太棒了,感谢唐楼主精彩的分享
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则