HR 使用Excel已经可以统计很多内容了,但 BI 的特点,大家知道是 动态 的。本文讲解如何在 PowerBI 中实现 HR 在离职人数的计算。
为了简化问题,这里仅仅使用两张表。
可以看到明显的特点是对员工离职表,仅仅记录必要的离职日期。
日期表。
值得注意的是,以上三个问题有一定的相关性。
在 PowerBI 中,编写 DAX 来实现复杂计算逻辑时,常常会进入的坑包括:
分别来看度量值的实现:
KPI.人数.离职.当期 = COUNTROWS( VALUES( Data[工号] ) )
KPI.人数.所选.全部历史 =
CALCULATE( COUNTROWS( VALUES( Data[工号] ) ) , REMOVEFILTERS( 'Date' ) )
KPI.人数.离职.累计 =
CALCULATE(
[KPI.人数.离职.当期] ,
FILTER( ALL( 'Date'[日期] ) , 'Date'[日期] <= MAX( 'Date'[日期] ) ) ,
Data[离职时间] <> BLANK()
)
KPI.人数.在职.当期 = [KPI.人数.所选.全部历史] - [KPI.人数.离职.累计]
首先,注意命名:
这里我们推荐使用 . 分隔符命名法。其约定在于:将主要的事情放在前面,将限定的部分放在后面,与 CALCUALTE 的写法类似。
这是有原因的:
其次,注意动态性的保持与屏蔽。
所谓动态性,就是当用户选择切片时,可以仍然起到筛选作用。但是否应该起到筛选作用,设计师应该提前想好。在本例中,当用户选择不同部门或职能时,那么所有的计算应该在该限定下完成,因此,我们必须保持这个动态性。
这就要求我们在使用 ALL 函数时,尽量作用到列,而不是一下将这个表都 ALL 掉。
如下:
KPI.人数.离职.当期 = COUNTROWS( VALUES( Data[工号] ) )
对人数的计算,应该以员工编号作为唯一标识,因此使用该列,同时,我们希望这个计算保持可被筛选的特性,因此使用 COUNTROWS( VALUES( T[C] ) ) 的固有定式。
KPI.人数.所选.全部历史 =
CALCULATE( COUNTROWS( VALUES( Data[工号] ) ) , REMOVEFILTERS( 'Date' ) )
这里希望计算所有员工,因此要清除日期表 Date 的影响,在 2019.9 月,DAX 中引入了更加贴切的 REMOVEFILTERS 函数来实现这个业务语义。
KPI.人数.离职.累计 =
CALCULATE(
[KPI.人数.离职.当期] ,
FILTER( ALL( 'Date'[日期] ) , 'Date'[日期] <= MAX( 'Date'[日期] ) ) ,
Data[离职时间] <> BLANK()
)
这是这里最复杂的一个公式,其积累求和的定式为:
CALCULATE(
[Measure] ,
FILTER( ALL( 'Date'[日期] ) , 'Date'[日期] <= MAX( 'Date'[日期] ) )
)
首先要理解这个定式,但在该案例中仅仅这样是不行的,我们需要在离职的数据中考虑,因此多加了一个筛选条件。
我们在此前的文章中讲解过上述定式,但几乎 99.9 %的老铁还是搞不明白,烧脑时刻来了。为了便于说明,我们重写一遍:
CALCULATE(
[Measure] ,
FILTER(
ALL( 'Date'[日期] ) ,
'Date'[日期] <= MAX( 'Date'[日期] )
)
)
以下为分析:
整个定式的实际如下:
CALCULATE(
[Measure] ,
FILTER(
ALL( 'Date'[日期] ) ,
'Date'[日期] <= MAX( 'Date'[日期] )
),
REMOVEFILTERS( 'Date' ) // 由于'Date'[日期]被筛选,本行由DAX引擎自动添加
)
这里需要大家反复阅读。
再谈 MAX( ‘Date’[日期] ) ,在上面的解释中,为了连贯,没有详细解释 MAX( ‘Date’[日期] ) ,这里为了彻底让老铁们明白这个问题,我们不妨打破砂锅讲到底:MAX( ‘Date’[日期] ) 会被 DAX 引擎转为 MAXX( ‘Date’ , ‘Date’[日期] ),我们进一步重写一次这个定式,请注意用户用手输入的公式:
CALCULATE(
[Measure] ,
FILTER(
ALL( 'Date'[日期] ) ,
'Date'[日期] <= MAX( 'Date'[日期] )
)
)
将被DAX引擎转为:
CALCULATE(
[Measure] ,
FILTER(
ALL( 'Date'[日期] ) ,
'Date'[日期] <= MAXX( 'Date' , 'Date'[日期] ) // 由 DAX引擎 转换
),
REMOVEFILTERS( 'Date' ) // 由于'Date'[日期]被筛选,本行由DAX引擎自动添加
)
因此,我们总结如下:
综上,我们实现了度量值的累计计算。
本文值得反复阅读,直到您彻底清晰地理解这个重要的定式:
CALCULATE(
[Measure] ,
FILTER(
ALL( 'Date'[日期] ) ,
'Date'[日期] <= MAX( 'Date'[日期] )
)
)
如果实在不能逾越,可以这样理解:
VAR vDate = MAX( 'Date'[日期] )
RETURN
CALCULATE(
[Measure] ,
FILTER(
ALL( 'Date'[日期] ) ,
'Date'[日期] <= vDate
)
)
这并不是为了说明 DAX 的复杂,在罗叔彻底理解类似这样的定式以后,编写DAX的感觉会变得更加自然,不必每次都真正思考筛选上下文在做什么,一些定式会帮助我们走在正确的感觉上,只要略微调整就可以满足我们的业务需求,如果实在需要刨根问底,可以像这样一步步拆解研究,当然这个过程需要一定的耐心。看过本文,相信你的DAX能力又进阶到了一个新的Level。