天天看点

多用度量值,少用新建列:一个度量值解决分月均摊

社群里有朋友提出这么一个问题:

问题

这是原始数据:

多用度量值,少用新建列:一个度量值解决分月均摊

这是想要的结果:

多用度量值,少用新建列:一个度量值解决分月均摊

结果呈现:

多用度量值,少用新建列:一个度量值解决分月均摊

看到这个问题,首先第一感觉,好像是非常简单的,获取每一个合同编号的起始月,然后均摊、求和就可以。

但是仔细一想,并没有那么简单。

解决方案

首先,第一行的2020.1.1-2021.12.31总共处在12个月,然而第二行的2021.1.29-2022.1.29却是占了13个月份。

很明显,全部的合同都是1年期,也就是12个月,不能均摊在13个月。

所以第一个问题就是就要定义到底是哪12个月。

经过一番讨论,确认:如果合同的起始日期为当月的15号之前(含),那么就从当月算起共12个月,如果是15号之后(不含),那么就从下个月算起共12个月。

比如2021.1.29-2022.1.29算作2021.2-2022.1这12个月的;2021.1.14-2022.1.13算作2021.1-2021.12这12个月。

第二个问题:结果的呈现带着“年月”这个维度,因此需要写一个日期表:

Power BI创建日期表的几种方式概览

由于表中只需要一个年月维度,我们简化一下:

日期表 = 
 GENERATE (
 CALENDAR ( DATE ( 2020, 1, 1 ), DATE ( 2022, 12, 31 ) ),
 VAR currentDay = [Date]
 VAR year = YEAR ( currentDay )
 VAR month = FORMAT ( currentDay, "MM" )
 RETURN ROW (
 "年度月份", year&month
 )
 )           

复制

第三步:写度量值

思路:

  • 根据起止日期列出期间的所有日期,并得到所在的月份A
  • 由起始日期是否在当月15日之前(含)来确定均摊的月份B
  • 通过筛选月份确定当月是否在以上B表中,如果在就返回分摊费用

统统这些,我们都可以直接在度量值中写出来。

  • 根据起止日期列出期间的所有日期
var date_begin=SELECTEDVALUE(data[起始日])
var date_end=SELECTEDVALUE(data[终止日])
var date_table=
GENERATE (
 CALENDAR ( date_begin, date_end ),
 VAR currentDay = [Date]
 VAR year = YEAR ( currentDay )
 VAR month = FORMAT ( currentDay, "MM" )
 RETURN ROW (
 "年度", year ,
 "月份", month,
 "年度月份", year&month
 )
 )           

复制

  • 得到所列的日期所在的月份表A

用SUMMARIZE函数来实现。

  • 由起始日期是否在当月15日之前(含)来确定均摊的月份表B
var a=TOPN(12,month_table0,[年度月份]*(-1))
//此处用了一个技巧,*(-1)来选择最小的12个月份
var b=TOPN(12,month_table0,[年度月份]) 
IF(
    RIGHT(date_begin,2)<="15",
    return a,
    return b
)           

复制

  • 通过筛选月份确定当月是否在以上B表中,如果在就返回分摊费用

使用CONTAINSSTRING和CONCATENATEX来确定所筛选的月份是否在以上的B表中。

将两个维度和度量值拖到矩阵中:

多用度量值,少用新建列:一个度量值解决分月均摊

OK!

后记

解决该问题其实可以使用新建列,但步骤上其实都差不多。

最近在研究流数据集,流数据集中是无法通过创建新列或者进行PQ处理的,甚至连数据格式都无法更改,能做的只有创建复杂度量值。

因此对于一些问题,最近是不考虑使用新建列的方式,而只考虑采取新建度量值进行聚合运算来解决。

这样做的好处是,模型会简单轻便一些;但坏处是掉头发会严重,而且虚拟表中的结果你是没法直接看到的,所以写的时候就很难受了。

不过,解决办法也不是没有,可以使用DAX studio,比较直观地看到表,因此最近也频繁使用起了它。