【DAX 系列】高清图解迭代原理并弃用 EARLIER
- 2020 年 2 月 17 日
- 筆記
到底什么是迭代?本文专为您准备。

首先,请死记:筛选和迭代是数据分析过程中的两大重要特性。
- 筛选,帮助我们从宏观到微观;
- 迭代,帮助我们具体考察每一个微观元素。
这也是 DAX 中,筛选上下文和行上下文的设计学来由。本文会非常简单地让您搞清楚迭代的概念。
开始。
理解迭代
很多从事业务的小伙伴问:到底什么是迭代?
精确地讲,迭代,是对一个集合中元素的遍历。
如下所示:

对于一个表的迭代,由于表是行的集合,每一行都表示同类事物的不同个体,如:不同的每一笔订单。很自然地可以将对表的迭代理解为对表中的行集合的迭代。
我们可以脑补一个箭头(例如:上图的右侧),这个箭头用来对表的行集合进行遍历,值得注意的是,我们不用关心它是怎么做到遍历的,不重要,只要知道表被遍历了。
在遍历的时候一般顺便可以做点坏事,例如,记住遍历过的每个值,这样就有了:
SUM.Value = SUM( SomeTable[Value] ) \ 本质上等价于:SUM.Value = SUMX( SomeTable , SomeTable[Value] )
SUMX 的含义是:
- 对 SUMX 的第一个参数(某个表),进行迭代;
- 在迭代中,每次执行第二个参数,如: 取出值;
- 加总它们。
如果你没什么感觉就对了。因为 SUMX 在这个例子中根本没干什么坏事。
在迭代中做坏事
SUMX 可以做很多坏事,例如:
Order.Sales = SUMX( Order , Order[Volume] * RELATED( Product[Price] ) )
这个案例中 SUMX 就做了坏事了。
业务人员想算销售额,而订单中没保存单价,但可以从与订单关联的产品表中找到单价,那么销售额的计算就可以是:
- 迭代订单;
- 对每一笔订单,找到对应的单价,当前销售额=相关单价×当前数量;
- 再加总它们。
这个坏事就很坏了,没有 SUMX 只有 SUM 就很难受。
此外,SUMX 还可以做很多坏事,例如:
【DAX 系列】总计行问题终极解决方案 中大量使用了 SUMX。
去 ↑ 挑战下脑力吧。
多层迭代
如果迭代一层没有让你晕菜,请看二层迭代:

左边每迭代一步,右边与之对应要迭代一轮。
典型应用就是 ABC 分析:
ABC分析 中有这样的累计度量值:
KPI % = VAR vCurr = [KPI] VAR vItems = FILTER( ALLSELECTED( Model_Product[子类别] ) , [KPI] >= vCurr ) RETURN CALCULATE( [KPI] , vItems ) / CALCULATE( [KPI] , ALLSELECTED( Model_Product ) )
出图如下:

其中,上面的折线就是一个积累占比,其逻辑如下:
- 迭代产品[子分类],令 vCurr = 当前元素的[KPI]; (相当于上面的绿色箭头)
- 对于每个 vCurr,重新迭代产品[子分类],(相当于上面的黄色箭头)
- 如果黄色箭头指向元素的KPI大于当前绿色箭头指向元素的KPI则保留
- 内圈迭代完成,剩下了 vItems 是在迭代中胜出的元素
- 求这些 vItems 的 KPI 与整体 KPI 的比值 %。
这就是比当前元素大的积累元素的 KPI 占比%。
构成了 ABC 分析中的 % 折线。
用 VAR 彻底代替 EARLIER
很明显,我们有时候在多层迭代时,需要用内圈迭代的元素(黄色)来和外圈迭代的元素(绿色)进行对比,这就需要 EARLIER 了,其含义为更早的迭代,精确讲是更早的迭代中的行。
当我们脑子绕不过来的时候,我们永远可以这么做:
VAR vCurrKPI = [KPI] // 绿色元素 VAR vItems = FILETER ( SomeTable , [KPI] ? vCurrKPI )
其中,FILTER 会创建一个内圈迭代环境,那么 [KPI] 就是内圈的黄色值,而 vCurrKPI 就是外圈的绿色值。
迭代器
现在就应该可以充分理解什么是迭代器了,那么我们可以看得见它吗?看不见。
原因如下:

我们说到了迭代器是用来迭代的,迭代是用来干坏事的,如果光迭代不干坏事,那不是白迭代了。但是到底干什么坏事呢,有很多种坏事,例如:
- SUMX,迭代时取出来计算后求和。 干得坏事是求和。
- FILTER,迭代时按某个条件过滤。 干得坏事是过滤。
- ADDCOLUMNS,迭代时,添加一列,并算出对应行中的元素。 干得坏事是加一列。
因此,我们可以发现:迭代 + 干坏事是不可分割的整体。
- 迭代是基础,没有迭代没法干坏事;
- 干坏事是目的,不干坏事白迭代。
因此,在 DAX 中,所有带有需要处理集合中元素语义的功能都是干坏事,都内部包裹了一个看不见的迭代器。
总结
迭代,是很自然的。当你的业务逻辑涉及到对一堆元素(如:表行)进行遍历并在每一步都做点坏事的时候,一定会自然而然地用到某些函数,这些函数自然而然的都包裹了一个看不见的迭代器。
记得,在迭代的时候做坏事,不做坏事,DAX 不爱。
祝你玩得开心。