网络上有不少关于DAX 函数 CALCULATETABLE 与 FILTER 不同之处的文章,不过源数据没有展示,主要是源数据太多,不便展示。问题来了,许多时候我们就是要讲眼见为实,不然还是难解疑窦。这正是本文要解决的痛点!
说明:本文数据皆为模拟,所统计的点也不一定有很强的业务意义,仅为讲清楚CALCULATETABLE 与 FILTER的区别。
请看源数据:
接下来要统计各种口味的行数分别有多少,以便指定某个口味对应数量时输出结果。以下为透视的各口味统计表,见《库存表透视》:
从《库存表透视》可以看到,原味有5行数据。现在,我们开始切入正题。
对比1:
从上面的截图可以看到,CALCULATETABLE 和 FILTER 两个表达式返回的结果是一致的。曾经我一度困惑过,为什么是一致的,却为啥要搞出这两个函数来呢?深究一下,其实不然。两个函数的运行方式不一样,各自有适用的场景(只是部分场景可以通用)。请继续往下看:
红框处,看到了吗?FILTER 和 CALCULATETALBE返回的结果是不同的。FILTER 返回的表中,口味是原味,这个没错,但是,前面你肯定有发现,原味的行数实际上只有5行,所有口味的行数加在一起才是11行。而CALCULATETABLE返回的是正确的结果。
现在我们来深扒一下两个函数中的两个参数。第一个参数以及它的执行结果如下:
可以看到,第一个参数执行的结果里列出了每个口味,但对应的行数都是所有口味的行数加总在一起的结果,也就是都是11行。我们这里且不管它对还是不对。接下来在看第二个参数。第二个参数我们手工在《库存表》里筛选出来:
从这两个参数的结果,我们可以从FILTER和CALCULATETALBE执行的顺序来推断。不改变参数的情况下,如果要得到正确的的结果,FILTER应该先执行第二个参数,得到如图6所显示的表,然后基于图6再执行第二个参数。第二个参数的意思就是,先提取出口味的唯一值(也就是多次出现的口味,只提取一个),然后把行数附在第二列,这样就可以得到与CALCULATETABLE一样的结果。(注意措辞,我这里说的是“把行数附在第二列”,而不是“把对应口味的行数附在第二列”,留个悬念,我们后续讨论。)
根据以上的推断,我们可以得到结论:
FILTER与CALCULATETABLE计算逻辑不一样。FILTER先计算第一个参数,得到图5的结果,然后再执行第二个函数,把原味的那一行数据检索出来,于是就得到了原味有11行的结果。CALCULATETABLE正好相反,它先执行第二个参数,把符合指定口味的数据检索出来,然后再执行第一个参数。