Power BI之DAX神功:答网友问07 什么是改变计算颗粒度
一、网友提问
问:我在看某权威书籍中,学到改变计算颗粒度,没看懂不知道怎么用?
答:如果有一天,你回到公元2000年,对着大家说“奥力给”他们肯定不知道是什么意思。如果你回到唐朝,跟他们说哈苏、莱卡、索尼大法,人们同样听不懂。不要在文字上研究,它是一个时代的产物,只是一个名字。
二、我们先看一个案例

我们想将休息日的信息Vlookup到日期表:
Excel工作表函数、M函数、VBA、Pandas等等都可以实现
但是,现在我们讲的是DAX原理,我们就用DAX方式
【新建列】工作日 = if(ISBLANK(LOOKUPVALUE('休息日'[休息日],'休息日'[休息日],'日期表'[日期])),1,0)
语法详见《孙兴华讲PowerBI火力全开》第2课 建模与关系函数

【度量值】总销售 = sum('销售表'[销售])
【度量值】总天数 = COUNTROWS('日期表') //共15天
【度量值】工作日天数 = sum('日期表'[工作日]) //共11天,因为有4天是休息日
【度量值】这期间的平均值 = DIVIDE([总销售],[工作日天数])

B员工总销售是66,工作日11天,平均每天是66/11=6
A员工总销售是6,工作日3天,但是它仍然是6/11=0.55
这明显是错的
我们要解决这个问题:让每个员工哪天有销售,就显示1,否则显示BLANK()
【度量值】优化工作日 = sumx('日期表',if([总销售]>0,[工作日天数]))

【度量值】优化这期间的平均值 = DIVIDE([总销售],[优化工作日])

友情提示:因为我的案例中,日期表就只有日期和工作日这两列。在你实际分析中,你的日期表中会有年,月,日,星期,等等
本案例中,我的明细是“每一天” 因为每一天中包含了年月日,所以在我的案例中SumX第1参数写'日期表'或Values('日期表'[日期])效果相同。换句话说:这张表的每一行,和日期列构成的这张表中的每一行是等效的。
【度量值】优化工作日 = sumx('日期表',if([总销售]>0,[工作日天数]))
【度量值】优化工作日 = sumx(Values('日期表'[日期]),if([总销售]>0,[工作日天数]))
原理步骤:
1.sumx是迭代函数,它在你指定的表中,迭代每一行。
2.【总销售】是度量值,放到你指定的表中是有筛选功能的。
3.sumx通过第二参数判断,总销售大于0就返回工作日天数,否则返回BLANK()。然而【工作日天数】也是度量值,也具有筛选功能,所以显示的是每日对应的工作日天数。(所以是1)
4.sumx写在度量值中,度量值将行上下文转换成筛选上下文。

二、案例进阶
刚才,我们只是说了一个最简单的情况,那复杂一些,例如有如下两张表:

A员工是2020年12月1日参加工作,数据是2020/12/1~2021/12/31 (1年零1个月)
B员工是2020年1月1日参加工作,数据是2020/1/1~2021/12/31(2年)
这家公司只有2020年12月按休息日休息了,其它时间全上班。
我们先通过《孙兴华讲PowerBI火力全开》笔记第27课03中的动态日期表,新建日期表
你看到一些书籍上举例,人家没有使用动态日期表,所以会出现很多空白日期
但是,实际工作中我们都使用动态日期表,从你销售表中日期列的最小日期到最大日期生成一个连续且不重复的日期表。
【新建表】
日期表 = ADDCOLUMNS(
CALENDAR(FIRSTDATE('销售表'[日期]),LASTDATE('销售表'[日期])),
"年", YEAR ( [Date] ),
"季度", ROUNDUP(MONTH([Date])/3,0),
"月", MONTH([Date]),
"周", weeknum([Date]),
"年季度", year([date]) & "Q" & ROUNDUP(MONTH([Date])/3,0),
"年月", year([Date]) * 100 + MONTH([Date]),
"年周", year([Date]) * 100 + weeknum([Date]),
"星期几", WEEKDAY([Date])
)
再通过新建列确定休息日和工作日:
【新建列】工作日 = if(ISBLANK(LOOKUPVALUE('休息日'[休息日],'休息日'[休息日],'日期表'[Date])),1,0)

【度量值】总销售 = sum('销售表'[销售])
【度量值】工作日天数 = sum('日期表'[工作日])
【度量值】优化工作日 = sumx(VALUES('日期表'[月]),if([总销售]>0,[工作日天数]))
【度量值】这期间的平均值 = DIVIDE([总销售],[优化工作日])
如果,我们SumX函数第一参数只使用了【月份】列生成的表

为什么A员工2020年23天,2021年365天,应该累计365+23=388天,可是显示和B员工一样都是723天?
因为sumx第1参数用错表了!我们上一个案例年月日都有,所以选择日期表的每一行和日期表的日期列是一样的。
这个案例,有年和月,你是不是应该选年和月?

原理:
因为你之前没有指定是哪一年,所以A员工只看月份,他12个月都有数据,因为2021年全年12个月他都有销售,所以总计显示他与B员工是一样的
当你指定了【年月】,这时,A员工2020年只有1个月有销售,2021年是全年有销售,他就会计算这13个月的工作日天数。
当你的公式只能对明细生效,不能对总计生效时,我们想办法让它对总计生效,就是改变计算颗粒度。

《孙兴华讲PowerBI火力全开》PowerBI必学课程
https://www.bilibili.com/video/BV1qa4y1H7wp
《DAX神功》文字版合集:
https://www.bilibili.com/read/readlist/rl442274
《DAX神功》视频版合集:
https://www.bilibili.com/video/BV1YE411E7p3
PowerBI(DAX函数)、PowerQuery(M函数)、Python办公自动化、Python爬虫、Python数据分析、ExcelVBA、WordVBA、AccessVBA、MySQL等等