美文网首页DAX圣经DAX圣经
【DAX圣经】第三章:使用基本表函数(2)

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

作者: daxbi | 来源:发表于2018-05-16 18:43 被阅读587次

    理解 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 作为标量表达式是很常见的,并且在本书中反复出现。

    相关文章

      网友评论

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

        本文链接:https://www.haomeiwen.com/subject/khdmdftx.html