CALCULATE

CALCULATE 庖丁解牛系列-扩展表(2)

2018-06-28  本文已影响468人  PowerBI非官方

    CALCULATE 庖丁解牛系列-- 扩展表(2)

  (该部分内容为《DAX圣经》第10章的第二节简体笔记修改而来)

    扩展表

      正如通过阅读前面的所有章节所看到的,理解计算筛选、筛选传递、筛选转换以及筛选器简化等,是DAX中需要学习的非常重要的技能,掌握了它们,你才能更准确理解DAX如何计算表达式。
      在前面的所有描述中,我们给出了理解计算筛选的一个稍微简化的定义。事实上,我们总是讲将在本书的后面,将让了解DAX计算筛选的所有内部信息。这一刻已经到来:你即将开始学习计算筛选中最隐式的秘密!
      在展示完整的解释之前,先来回顾一下到目前为止对计算筛选的了解:
    (1)DAX有两种筛选:行筛选和列表筛选。行筛选并不通过关系传播;
    (2)行筛选总是包含单个的列值,并通过CALCULATE或迭代引入行筛选;
    (3)列表筛选按照定义所指示的关系那样传递;
    (4)列表筛选可以在表或列上操作。如果在列上工作,它只筛选该单列表。在处理表(多个列表)时,它会筛选该表的所有列。
      所有这些陈述都是正确的。然而,为了完成我们对于计算筛选的进一步理解,需要再了解:   

      在DAX中,计算筛选的基础是扩展表的概念。

      在DAX中,每个表都有相应的扩展模型。表的扩展模型除包含原始表的所有列之外,还应加上可以通过多对一关系筛选的原始表的表列。例如,考虑图10-17中的模型。

      图10-1(1)使用这个简单的模型来学习扩展表的概念。
Sales与Product表有着多对一的关系,因此扩展版本的Sales包含了Product的所有列。
        一方面,从Product表开始的重复过程,可以很容易地看到,扩展版本的Sales表其实包含整个数据模型。
        另一方面,Product-“产品”的扩展版本包含“产品”、“产品子类别”和“产品类别”的所有列。
        Date-日期表则需要更多的关注。事实上,它可以被Sales表筛选,因为连接它们的关系是双向的。这种双向关系系是并不是一对一,而是一对多的关系。因此,Date表的扩展版本仅包含Date表本身的列,哪怕Date列可以被销售、产品、产品子类别和产品类别列筛选。即使因为双向关系而发生筛选,我们也不将它归入扩展列,相反,我们称它为筛选列。为了进行这种描述:

        筛选列和扩展列的行为方式是相同的,即使它们是不同的概念。

      因此,目前暂时将它们放在一边,只有在本节结束时,才会更详细地讨论筛选列和扩展列之间的区别。当对数据模型中的其他表重复相同的引用时,将创建表10-4所示的扩展表。

      表10-1(2) 表的扩展版本。

      扩展表是一个很有用的概念。因为,它们为每个表显示了将其列表筛选传递到原始表的列的列表。 例如,如果以Product表为例,可以很容易地检查:如果筛选该表的扩展模型中的任何列,那么,引擎也会同样筛选到Product表的列。最重要的是:

      DAX使用扩展的表在列表筛选中可放置任何筛选器。

        为了更好地理解它,我们在图表上进行可视化扩展的表设置,如图10-18所示。

      图10-2 可视化了图表上的数据模型,使查看扩展表变得更容易(直观)。图表中列出了模型的行中的所有列和每个表上的每个列表。我们给单元格着色以表示内部的三种列:(注:DAX数据模型可能存在这三种列表组合方式的一种或多种)。

      本  列:是最初属于表的那些列,即最初存在于数据模型里的列表;
      派生列是按照关系添加到扩展表中的列;
      筛选列:是可以筛选表的列,即使它们不属于表的扩展版本。

      在列上放置筛选器时,你可以对包含该列的行进行颜色化(对应映射原则),以直观地指示筛选了哪些列表。如果你写了以下内容:

        [RedSales] := CALCULATE (SUM ( Sales[Quantity] ), Product[Color] = "Red")

      然后,由于筛选器位于Color列上,相应的图表将在图10-3中可见。

        图10-3 给列的线条着色后,可以清楚地看到哪些表被筛选了(被颜色行穿越的列表)。

        Color 列上是一个列表筛选器。即对单个列进行操作的筛选器。因此,现在可以定义列表筛选器的一般规则:

      “放置在列上的筛选器将对所有包含它的扩展表进行筛选操作”。

      正如我们所看到的,这条规则与前面提到的所有规则相同,当时谈论的是列表和关系。列表筛选不真正通过字段关系“传递”。它将其行为应用于包含该列的所有表,因为这些列同样属于扩展表。
      请注意:Color-颜色上的筛选器也会传递到Date表,即使技术上Color-颜色不属于扩展模型的Date表,这是双向筛选工作的效果。同时也请注意,Color列上的筛选器是通过筛选列而不是通过扩展表传递到Dates表的。
      在内部,DAX引入特定的筛选代码以使双向关系工作,而对扩展表的筛选则根据引擎的工作方式自动执行。正如我们所说,这种差别只是内部的(无须干预),但明白这一点却很重要。

      你已经知道,可以通过使用传递整个表的FILTER函数,来创建列或表表筛选器(与前面看到的类似)。那么,表筛选器是如何工作的?其实,它们也在引用扩展的列表集。     
      事实上:无论何时,只要将表作为CALCULATE中的筛选条件,实际上都是在对扩展的表进行筛选。也就是说:

      CALCULATE的列表筛选,总是在筛选扩展的表。

        为了理解它,请看这两个度量定义:

[NumOfCategories] : = COUNTROWS ( 'Product Category')
[NumOfCategoriesFilteredByProduct] : =
CALCULATE ( COUNTROWS ( 'Product Category' ),  Product )

      第一个度量,计算categories-类别数;
      第二个度量,也是计算categories-类别数。与前一个公式不同的是,它引用了包含Product表的列表筛选 ( 当然,这是在当前列表条件下筛选)。结果见图10-4,其中在行上引用了包含Product[Color]--产品颜色列。

      图10-4 这个透视表显示了在CALCULATE中应用表筛选器的效果。

      第一列--NumOfCollection总是显示相同的数字。原因是:在行上使用了Product[Color]-产品颜色列,如果你反过头查看图10-18中的扩展表图,Product表的扩展表并不包含Color列。
      因此,Color-颜色筛选对当前可见的类别行基数没有影响。但是,当你将Product表放入FILTER筛选中,这时使用的是Product-产品表的扩展表模型,它包含“产品”子类别的所有列,可见类别的数量将不再是8个,而是包含当前颜色的产品的类别数。

    CALCULATE使用列表作为筛选参数,将筛选其扩展表里的所有列表。

      因此,以下两项度量之间有很大差别:

[NumOfCategoriesFilteredByColor] : = CALCULATE (COUNTROWS ( 'Product Category' ),
      FILTER (ALL ( Product[Color] ),Product[Color] = "Green"))
[NumOfCategoriesFilteredByProduct] : = CALCULATE (COUNTROWS ( 'Product Category' ),
      FILTER (ALL ( Product ),Product[Color] = "Green"))

      虽然这两个度量看上去几乎相同,但事实并非如此。
      第一个选项。相当于只针对在Color列放置一个筛选器,因此,它的筛选效果不会包含Product[Color]列的扩展表(其他列被隔离)。因此,它对 Product Category-“产品类别”表没有影响。
      第二个选项。相当于在整个Product 动态扩展表上放置了一个筛选器。因为扩展的Product表包含Product扩展表的列,所以,第二个度量只计算包含Green-绿色产品的类别数,而第一个度量总是显示类别总数,如图10-21所示。

      图10-5 这个透视表显示了在CALCULATE中应用表筛选器的效果,

      让我们再看看派生列和筛选列之间的区别。

      前面已说过,Date的扩展表与Sales表存在双向关系,它不包含Sales列。在筛选日期时,它可以在Sales表上获得一个筛选器,因为扩展的Sales表包含Date表,相反则不行。最后一句是非常重要的,所以,我们想再次强调这个筛选的概念:
      Date表能筛选Sales表,即使扩展的Date表不包含Sales。

      然而,由于Date与Sales表有双向关系,而且扩展的Sales表包含整个数据模型。因此,我们认为Date表有一个定义整个模型的筛选集。当筛选模型中的任何列时,因为日期表的某个列筛选,同时并且理所当然也要筛选Date列。如果你定义一个简单的度量,例如:

      [NumOfDates] : = COUNTROWS ( 'Date' )

      你可以在透视表中使用它,并按Color颜色进行筛选,并为每种颜色获取当前该颜色的日期数,如图10-22所示。

        图10-6 颜色上的筛选器由于双向关系而被传递到日期表,

      这就是为什么,发生筛选是因为颜色属于日期的筛选列。
      尽管如此,Date的扩展模型既不包含颜色列,也不包含任何其他产品表的列。如果你创建了一组度量值来计算使用不同表作为筛选器的产品数量,则可以验证这一点;

[NumOfProducts] ;= COUNTROWS ( 'Product' )

[NumOfProductsFilteredByDate] ;= CALCULATE ( COUNTROWS ( 'Product' ), 'Date' )[NumOfProductsFilteredBySales] ;= CALCULATE ( COUNTROWS ( 'Product' ), Sales )

      NumOfProductsFilteredByDate度量在CALCULATE中使用Date作为筛选参数,后者是Date的扩展模型。而NumOfProductsFilteredBySales使用的是Sales的扩展模型。如图10-23所示,只有在筛选器中使用Sales时,筛选器才能传递到Product--产品表。这是因为Date的扩展模型不包含Product表里的列,而扩展的Sales则包含这些列。

        注:如果你觉得这样难理解,你始终可以使用最大的那个扩展表(一般为计算的事实表)

      图10-7仅最后一列显示了该期间销售的产品数量,因为它使用的是扩展的Sales表。Date表的扩展表并不包含任何Product列。
      扩展表是帮助你理解筛选器筛选传递方向的强大工具。
      实际上,它们是DAX中筛选器筛选传递理论的真正基础。这需要一些时间来介绍它们,因为它们的使用并不是很直观。我们更喜欢在它之前引入其他概念,以帮助你熟悉该语言。一旦掌握了扩展表的使用,你将发现很容易理解DAX是如何工作的。

      扩展表里使用ALLEXCEPT

      我们知道,除了作为参数传递的列外,ALLEXCEPT将对表的所有列执行ALL操作。不太明显的是:也可以在扩展表中使用ALLEXCEPT。例如,以下度量非常有效:

[SalesOfSameColorAndCategory] ;=
CALCULATETABLE (SUMX (Sales, Sales[Quantity] * Sales[UnitPrice]),
ALLEXCEPT ( Product, Product[Color], 'ProductCategory'[Category] ))

      实际上,产品的扩展模型也包含了Product Class-产品类别的所有列。也可以指定一个完整的表,而不是作为扩展表的一部分的表的所有列。例如,ALLEXCEPT的以下两个表达式是等效的:

      ALLEXCEPT(Product, 'Product Category' )
      ALLEXCEPT(Product,  'Product Category'[ProductCategoryKey], 'ProductCategory'[Category] )

      在 ALLEXCEPT第二个参数中指定的列表将从ALL条件中排除,并且该列表必须是第一个参数中指定的展开表的一部分。

      扩展列表与筛选列表的区别

      正如我们前面说过的,数据列表的扩展只会从列表关系的多端扩展到关系的一端。
      因此,即使产品表与产品子类别表有双向关系,产品表的扩展模型也包含子类别,但产品子类别表的扩展模型不会包含产品表。
        DAX引擎在表达式中引入筛选代码 (比如你可以:使用CROSSFILTER函数,以便使双向筛选工作变得像扩展方式一样。因此,在大多数情况下,代码将很好地工作,这就像表的扩展发生在两个方向一样(在双向的任意端都可以扩展)。
      因此,在图10-1和图10-2中看到:筛选列与派生列不同。筛选列是应用筛选器的列,这要归功于DAX引擎的这种行为,而不是因为扩展的表(它们并不是实际表的一部分)。

      然而,这种差异随着SUMMARIZE 或RELATED的使用而变得重要。例如,如果使用SUMMARIZE来根据另一个表来执行列表分组,则必须使用基表的扩展模型的某个列(即使用原列,而不能使用筛选列)。例如,下面的SUMMARIZE语句工作得很好:

EVALUATE
SUMMARIZE ( Product, 'Product Subcategory'[Subcategory] )

      下一个尝试根据产品颜色SUMMARIZE子类别的方法却不好:

EVALUATE
SUMMARIZE ( 'Product Subcategory', Product[Color] )

      结果导致的错误是:“输入表中找不到‘SUMMARIZE’函数中指定的“Color”列”。这意味着产品子类别的扩展模型应该不包含Product[Color]。

      类似地,RELATED的工作仅适用于属于扩展表的列。

      如果尝试使用筛选其中某个列,这一点就更明显了,它不是表的扩展模型的一部分。例如,即使这些列是筛选列,也不能使用其他表的列对日期表进行分组:

EVALUATE
SUMMARIZE ( Date, Product[Color] )

      只有一个特殊情况,如果一段关系是1:1关系,即表在两个方向扩展,这是一种定义为一对一的关系。然后将两个表扩展为另一个表。这是因为一对一的关系使两个表在语义上完全相同:一个表中的每一行与另一个表中的单个行有直接关系。因此,把这两个表看作是一个单独的表,理解为分成两组列表是正确的。


上一篇下一篇

猜你喜欢

热点阅读