到目前为止,我们已经介绍了不少的知识点,但都以原理居多,所涉及到的函数比较少,而且介绍函数时也没有结合具体的案例来介绍,大都只讲计值流程与注意事项去了。因此,本篇文章将介绍一个小案例,用来串联之前学过的内容。


  虽然目前介绍的函数比较少,但是各个函数嵌套起来使用也是很强大的,我们已经有足够的能力去解决一些问题了。我希望跟着我学习DAX的朋友都能够灵活使用我所介绍的各个知识点,而不要死板的套用,因为我所介绍的内容都比较倾向于原理,而不是倾向于应用的套路,所以一定要自己多去练习,多多举一反三。

  那下面就来看一下这个案例的问题描述:

  在这个案例中,我们要解决的事情有两个,一个是用矩阵来汇总各个产品的销售数量,另一个则是根据切片器选中的关键字来动态隐藏掉部分不需要的产品行标签。

  那么我们先来解决第一个事情,先创建一个矩阵,并把产品名称放入到行字段中,然后再新建一个能汇总销量的度量值,并把这个度量值放入到值字段中。其中,使用到的度量值表达式如下:

销售数量 = SUM('销售表'[销量])

  结果如下:

  那么接下来,我们来解决第二件事情。先来看一下问题的原始描述:“希望只显示包含切片器选中关键字的产品的销售数量”,从这个问题描述中我们可以知道以下几点信息:

  • 存在一个切片器,这个切片器要使用到关键字表中的关键字这一列
  • 问题描述中使用了“包含”这个词,因此切片器有可能是多选的,我们的解决方案也要支持多选时的情况
  • 不包含所选关键字的产品及其销售数量不能显示在矩阵中

  那么想要解决这个问题,我们需要解决以下几件事情:

  • 需要获取到矩阵在计算时的当前行标签,即需要判断的产品
  • 需要获取到切片器选中的关键字列表
  • 需要对每一个关键字进行判断,看看当前产品是否包含任意一个关键字
  • 如果当前产品不包含任意一个关键字,我们就要在矩阵中隐藏这个产品及其销售数量
  • 如果当前产品包含任意一个关键字,我们就要在矩阵中显示这个产品及其销售数量

  要解决的事情已经在上面列出了,那下面我们就来思考一下要用什么手段或方法来解决这些事情:

  • 行标签其实是一个筛选器,所以可以从销售表中的筛选上下文里提取当前行标签的值,而外部筛选上下文里的产品名称必定只有一个,所以我们可以使用MAX或MIN函数去获得
  • 切片器也是一个筛选器,所以可以从关键字表中的筛选上下文里获取选中的关键字列表,也就是需要返回一个单列表,这可以使用VALUES或DISTINCT函数完成
  • 为了避免切片器与行标签的筛选器互相影响,所以销售表与关键字表之间不能存在关系
  • 需要遍历每一个关键字,并判断当前产品是否包含正在遍历的那个关键字。既然需要遍历,那就要用到迭代函数,可以考虑使用FILTER函数。而判断文本包含,可以使用FIND或SEARCH函数,这两个函数也是继承于Excel
  • 判断是否包含任意一个关键字的标准,可以看FILTER返回的结果是否为空,若为空即不包含任意一个关键字,这可以使用ISEMPTY函数来判断表是否为空
  • 需要根据FILTER是否为空这一个条件来做计算分支,因此可能需要使用到IF函数
  • 最后就是需要在矩阵中隐藏不包含任意关键字的产品行标签,这个可以考虑使用矩阵的一个特性,那就是当行标签对应的所有值都为空时,该行标签就会自动隐藏。所以,我们需要使不包含任意关键字的产品行标签所对应的销售数量为空,才能达到自动隐藏的效果

  根据以上的分析,我们可以写出以下度量值:

关键产品的销售数量 = 
IF(
    ISEMPTY(
        FILTER(
            VALUES('关键字表'[关键字]),
            FIND('关键字表'[关键字],MAX('销售表'[产品名称]),1,0) // 1代表从首字符查找,0代表找不到时的替代结果
        )													// 0可以转换成FALSE
    ),
    BLANK(),
    SUM('销售表'[销量])
)

  将上述度量值放入矩阵的值字段中,结果如下:

  从上面的结果中可以看出,在明细行时的结果是没问题的,但是总计行的值却不正确。总计行的值不正确是因为我们使用了MAX函数去从行标签的筛选上下文里提取当前的产品名称,当在总计行时,不再有行标签提供筛选器,使得筛选上下文里可见的产品名称有多个,而MAX函数将获取到排名最大的那个产品名称,即C产品,而C产品不包含切片器选中的任意一个关键字,所以为空。

  那下面就来解决总计行的值不正确这一个问题,一个可行的方法就是在总计行里计算所有明细行的结果,再汇总起来。那么我们可以使用SUMX函数与VALUES函数配合,当在明细行时,由于存在行标签提供的筛选器,使得VALUES只返回行标签对应的单个值。当在总计行时,由于不存在行标签提供的筛选器,那么VALUES就会返回所有产品名称,然后SUMX再迭代计算每一个产品名称,最终再把所有结果汇总起来,即可达到目的。

  根据以上思路,我们可以写出以下改进后的度量值:

关键产品的销售数量2 = SUMX(VALUES('销售表'[产品名称]),[关键产品的销售数量])

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

  此外,再给出类似思路的另一个度量值写法,具体的度量值表达式如下:

关键产品的销售数量3 = 
CALCULATE(
    SUM('销售表'[销量]),
    FILTER(
        VALUES('销售表'[产品名称]),
        NOT ISEMPTY(FILTER(VALUES('关键字表'[关键字]),FIND('关键字表'[关键字],'销售表'[产品名称],1,0)))
    )
)

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


  从这个案例中,应该可以初步体验到DAX的魅力了吧,这种把逻辑用代码表达出来的感觉是不是很有意思呢。最后,建议各位动手亲自实现一下该案例,并好好总结消化。


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

  加入Q群