回忆是一座桥
却是通往寂寞的牢

12、理解筛选上下文

  在之前的文章中我们了解到:” 多个筛选器经过交互后可以合并成一个筛选器组合,然后该筛选器组合再去筛选模型中的数据,最后模型中各个表的可见数据组成了当前计值环境里的筛选上下文 “。因此,我们只需要把下面这两个过程搞清楚,就可以彻底掌握筛选上下文了:

  • 多个筛选器是如何合并成一个筛选器(筛选器间的交互方式)
  • 筛选器是如何筛选数据的(筛选器在表间关系上的传递)

  而在之前的文章里已经介绍了筛选器在表间关系上的传递过程,那么从本篇文章开始,将逐步介绍筛选器间的交互方式。本篇文章主要介绍标准筛选器间的交互方式。


  首先,任何筛选器间的交互方式都可以概括为如下:

  • 不同列上的筛选器之间的交互方式为相交
  • 相同列上的筛选器之间的交互方式为覆盖,用新增的筛选器去覆盖已有的筛选器
  • 初始筛选器之间的交互方式为相交

  其中,初始筛选器指的是数据透视表(矩阵)的行列标签、筛选页字段、切片器、钻取、图表联动等视觉对象或操作所提供的筛选器。而且,初始筛选器之间的交互方式均为相交,即使是相同列上的初始筛选器也是相交。需要注意的是,所谓的不同列,并不仅仅是指的列名不一致,还需考虑列所属的表,例如:’产品表'[产品名称] 与 ‘销售表'[产品名称] 这两个列,虽然它们的列名一致,但分别属于不同的表,那么这两个列也是非相同列,只有表名与列名均一致的列才是相同列。

  此外,上面所介绍的规则只适用于一般情况,并不是绝对的。在某些特殊情况下,比如使用了筛选调节器或者是定义了日期表等情况下,相同列上的筛选器也是可以相交的,而非相同列上的筛选器也有可能是覆盖。当然,这毕竟是特殊情况,比较少出现,记住上面的规则就足以应付百分之八十的情况了。


  标准筛选器的相交行为

  筛选器间的相交行为从语义上可以理解成数学意义上的取交集,但实际上,相交行为产生的是笛卡尔积组合。具体如下图所示:

  在所生成的筛选器组合中,将按照同行为且异行为或的关系去筛选模型中的数据(类似于Excel高级筛选的条件区域)。

  标准筛选器的覆盖行为

  当某个列上设置了多个筛选器时,那么这些筛选器就会有冲突,比如一个筛选器说要筛选A,而另一个筛选器却说要筛选B,由于都是同一个列上的筛选器,并不能以相交行为和平共处,因此必须按照一定的规则来决定出最终的胜利者,谁赢了就听谁的。那么这个规则就是新增的筛选器覆盖旧的已有筛选器,这个覆盖行为可以理解成直接移除旧的已有筛选器。具体如下图所示:

  在上图中,只展示了单个新增筛选器去覆盖单个已有筛选器,但有时候会遇到单个新增筛选器去覆盖多个已有筛选器的情况(例如初始筛选器里有多个相同列上的筛选器),甚至还有更复杂的情况,但这都适用同一个准则,那就是用新增的筛选器去覆盖已有的筛选器,无论已有筛选器的数量有多少,只要是与新增筛选器同列的,均会被覆盖或者说是移除。


  为了更好地理解筛选器间的交互方式,下面将用一些简单的例子来巩固理解。在介绍前,先来看一下要用到的数据与数据模型:


  相交行为举例

  先来看第一个例子,使用到的度量值公式如下:

销售金额 = SUM('订单表'[销售额])

度量值 1 = CALCULATE([销售金额],'产品表'[产品名称] IN {"鼠标","键盘","耳机"})

  首先,创建一个矩阵视觉对象,把产品表中的产品类别列放入行字段,并把销售金额与度量值1放入值字段,结果如下图所示:

  在上图展示的报表环境中,初始筛选器只有一个,那就是矩阵的行标签所提供的筛选器,对于销售金额度量值,它的计值流程在之前的文章中已经介绍过了就不再重复,下面以度量值1在行标签为电脑外设时的结果312为例,简单介绍其计算过程:

  1. 外部的已有筛选器为:’产品表'[产品类别] = "电脑外设"
  2. 新增的内部筛选器为:’产品表'[产品名称] IN {"鼠标","键盘","耳机"}
  3. 上面两个筛选器为非相同列上的筛选器,故交互方式为相交,产生的筛选器组合如下:
    '产品表'[产品类别] = "电脑外设" && '产品表'[产品名称] = "鼠标" ||
    '产品表'[产品类别] = "电脑外设" && '产品表'[产品名称] = "键盘" ||
    '产品表'[产品类别] = "电脑外设" && '产品表'[产品名称] = "耳机"
  4. 经筛选后得到订单表的筛选上下文,如下图所示:
  5. 销售金额度量值在上述的筛选上下文中计值,将把销售额列上的可见值汇总起来,最终得到汇总值:312

  下面再来看一个相交的例子,用到的度量值公式如下:

度量值 2 = 
CALCULATE(
    CALCULATE(
        [销售金额],
        '产品表'[产品代码]="sj002" //该代码指代的产品为:耳机
    ),
    '产品表'[产品名称] IN {"鼠标","键盘","耳机"}
)

  把上述度量值继续放入到矩阵的值字段中,结果如下:

  CALCULATE函数的计值流程可以简单概括为:先在外部计值环境下计算各个内部筛选器参数,然后内部筛选器修改外部计值环境,最后计算器参数(第一参数)在修改后的计值环境里计值。所以,上面这个嵌套CALCULATE函数的度量值中,最外层的内部筛选器参数最先与外部筛选器交互,之后内层CALCULATE的内部筛选器参数再参与交互。下面以度量值2在行标签为手机配件时的结果218为例,简单介绍其计算过程:

  1. 外部的已有筛选器为:’产品表'[产品类别] = "手机配件"
  2. 外层CALCULATE新增的内部筛选器为:’产品表'[产品名称] IN {"鼠标","键盘","耳机"}
  3. 上面两个筛选器为非相同列上的筛选器,故交互方式为相交,产生的筛选器组合如下:
    '产品表'[产品类别] = "手机配件" && '产品表'[产品名称] = "鼠标" ||
    '产品表'[产品类别] = "手机配件" && '产品表'[产品名称] = "键盘" ||
    '产品表'[产品类别] = "手机配件" && '产品表'[产品名称] = "耳机"
  4. 外层CALCULATE的计算器参数在上述筛选器组合下计值
  5. 内层CALCULATE的外部计值环境已有的筛选器为:’产品表'[产品类别] = "手机配件",’产品表'[产品名称] IN {"鼠标","键盘","耳机"}
  6. 内层CALCULATE新增的内部筛选器为:’产品表'[产品代码]="sj002" //该代码指代的产品为:耳机
  7. 上面三个筛选器为非相同列上的筛选器,故交互方式为相交,产生的筛选器组合如下:
    '产品表'[产品类别] = "手机配件" && '产品表'[产品名称] = "鼠标" && '产品表'[产品代码]="sj002" ||
    '产品表'[产品类别] = "手机配件" && '产品表'[产品名称] = "键盘" && '产品表'[产品代码]="sj002" ||
    '产品表'[产品类别] = "手机配件" && '产品表'[产品名称] = "耳机" && '产品表'[产品代码]="sj002"
  8. 经筛选后得到订单表的筛选上下文,如下图所示:
  9. 销售金额度量值在上述的筛选上下文中计值,将把销售额列上的可见值汇总起来,最终得到汇总值:218

  在上面这个例子中,我对内层CALCULATE的外部计值环境的描述采用了筛选器的形式,当然你也可以采用筛选器组合的形式来理解,这都是没问题的,因为它们都能生成同一个筛选上下文。在某些情况下我也会采用筛选器组合的形式来理解外部计值环境,甚至是两种方式混用。具体采用何种方式来理解外部筛选上下文主要是取决于你个人,哪种方式更容易理解就采用哪种。


  覆盖行为举例

  先来看第一个例子,用到的度量值公式如下:

销售金额 = SUM('订单表'[销售额])

度量值 3 = CALCULATE([销售金额],'产品表'[产品名称]="U盘") 

  首先,新建一个矩阵视觉对象,把产品表的产品名称列放入行字段,并把上面两个度量值放入到值字段中,结果如下:

  如上图所示,度量值3的所有值均为”U盘“行标签所对应的值,我相信大多数人都遇到过这种整列均为同一个值的情况,但却搞不清楚原由。那下面就以度量值3在行标签为耳机时的结果147为例,简单介绍其计值流程:

  1. 外部的已有筛选器为:’产品表'[产品名称] = "耳机"
  2. 新增的内部筛选器为:’产品表'[产品名称] = "U盘"
  3. 上面两个筛选器为相同列上的筛选器,故交互方式为覆盖,用新增的筛选器覆盖已有的筛选器,产生的筛选器组合如下:
    '产品表'[产品名称] = "U盘"
  4. 经筛选后得到订单表的筛选上下文,如下图所示:
  5. 销售金额度量值在上述的筛选上下文中计值,将把销售额列上的可见值汇总起来,最终得到汇总值:147

  上面是行标签为耳机时度量值3的计值流程,但其它行标签所对应的计值流程也是一致的,仅仅只是外部筛选器筛选的内容不一致,内部新增加的筛选器都是筛选的"U盘"产品,而内部筛选器与行标签提供的筛选器又属于相同列,因此总是发生覆盖行为,用新增的内部筛选器去覆盖行标签提供的筛选器,使得结果总为"U盘"产品对应的销售金额,即147。

  下面再来看一个覆盖的例子,用到的度量值公式如下:

销售金额 = SUM('订单表'[销售额])

度量值 4 = 
CALCULATE(
    CALCULATE(
        [销售金额],
        '产品表'[产品类别] = "电脑外设"
    ),
    '产品表'[产品名称] = "手机壳"
)

  再新建一个矩阵视觉对象,把产品表的产品类别列放入行字段,并把上面两个度量值放入到值字段中,结果如下:

  这一次,度量值4的所有值均为空,这种情况对初学者来说应该也遇到过不少次,那下面就以度量值4在行标签为手机配件时的结果为例,简单介绍其计值流程:

  1. 外部的已有筛选器为:’产品表'[产品类别] = "手机配件"
  2. 外层CALCULATE新增的内部筛选器为:’产品表'[产品名称] = "手机壳"
  3. 上面两个筛选器为非相同列上的筛选器,故交互方式为相交,产生的筛选器组合如下:
    '产品表'[产品类别] = "手机配件" && '产品表'[产品名称] = "手机壳"
  4. 外层CALCULATE的计算器参数在上述筛选器组合下计值
  5. 内层CALCULATE的外部计值环境已有的筛选器为:’产品表'[产品类别] = "手机配件",’产品表'[产品名称] = "手机壳"
  6. 内层CALCULATE新增的内部筛选器为:’产品表'[产品类别] = "电脑外设"
  7. 新增的筛选器:’产品表'[产品类别] = "电脑外设" 覆盖相同列上的已有筛选器:’产品表'[产品类别] = "手机配件",并与非相同列上的已有筛选器相交:’产品表'[产品名称] = "手机壳",产生的筛选器组合如下:
    '产品表'[产品类别] = "电脑外设" && '产品表'[产品名称] = "手机壳"
  8. 由于手机壳不属于电脑外设,在订单表中筛选不到任何数据,筛选上下文为空,如下图所示:
  9. 销售金额度量值在上述的筛选上下文中计值,由于不存在可见数据,故最终结果为空

  由于内层CALCULATE函数的内部筛选器与行标签所提供的筛选器属于相同列上的筛选器,所以内层CALCULATE函数的内部筛选器总是覆盖行标签提供的筛选器,然后再与外层CALCULATE函数的内部筛选器相交。但由于手机壳不属于电脑外设,导致筛选上下文总是为空,使得所有结果均为空。


  筛选器之间的交互方式只有两种,分别是相交与覆盖,它们的行为以及结果应该都是挺容易理解的。虽然筛选器之间的交互方式比较容易理解,但另一个考验也随之而来,那就是正确判断当前计值环境中有哪些已有筛选器,以及判断哪些筛选器是后面新增加的。只有正确判断出已有筛选器与新增筛选器,我们才能利用筛选器之间的交互方式去得到它们的筛选器组合,并进一步得到筛选上下文。因此,想要彻底掌握筛选上下文,不仅要知道筛选器之间的交互方式与筛选器在表间关系上的传递过程,还要知道哪些行为与函数能够产生筛选器。


  DAX系列文章中涉及到的案例文件,均已上传到QQ群:344353627,若有需要,可自行加群获取。

未经允许不得转载:夕枫 » 12、理解筛选上下文
订阅评论
提醒
guest
0 评论
内联反馈
查看所有评论