Power BI之DAX神功:第2卷第10回 初步理解时间智能计算过程
一、什么是时间智能
有些问题,你在搜索引擎查询时,答案会收录百科中,也会有很多专业的回答和总结,哪怕是搜索:什么是人。 都可以得到专业答案。
但是,当你输入:什么是时间智能
我保证,你只能搜到卖课的广告或者是帮助卖课人推广的广告。
他们大多给你一个这样的答案:时间段、始发站终点站、平移、平移间隔、重组时间段等等(无论字数长短,最终离不开这个圈)
你冷静的想一想,微软官方和《The Definitive Guide to DAX》都没有给你总结,证明它需要的不是“总结”!
二、创建日期表为什么避开CALENDARAUTO函数
《孙兴华讲PowerBI火力全开》第28课 动态日期表
日期表 = 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])
)

关于,CALENDARAUTO函数我个人不建议你使用,他从所有表中找所有日期列(不包含计算列),并不是从指定列中去找。
我举一个简单的例子:假如我做人力工作,我用上面的公式生成一张日期表,分析入职和离职情况:


我使用CALENDAR可以从指定表入职时间和离职时间中找到最小日期和最大日期生成一张日期表。
但是,使用CALENDARAUTO函数时:

它直接生成了1980年1月1日至2021年12月31日,因为它将员工生日也算进去了,且从开始日期所在年第一天至结束日期所在年最后一天生成日期表。
三、多个日期表的使用
建议使用《DAX神功》第1卷第21回 Calculate调节器USERELATIONSHIP函数
不建议你使用两个日期表分别与多端表建议一对多关系,这会给后期处理造成很大的麻烦。
四、理解基础时间智能计算
大多数网友看书看到这里就蒙了,别蒙!这里的知识很简单!前提是《DAX神功》你顺序的看过来,没有跳集。
只要你理解了 《DAX神功》第2卷第3回 计算移动平均值再次理解Filter+ALL 这节课就够了

【新建表】
日期表 = ADDCOLUMNS(
CALENDAR(FIRSTDATE('Sheet1'[日期]),LASTDATE('Sheet1'[日期])),
"年", 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])
)

度量值1 = CALCULATE([总销售],FILTER('日期表', '日期表'[Date]>=date(2021,1,1) && '日期表'[Date]<=date(2021,12,31)))
// 度量值1:筛选出2021/1/1~2021/12/31之间的销售,因为Filter使用的是表,所以可以筛选
度量值2 = CALCULATE([总销售],FILTER(all('日期表'), '日期表'[Date]>=date(2021,1,1) && '日期表'[Date]<=date(2021,12,31)))
// 度量值2:在度量值1的基础上使用了all(表),最终得到2021/1/1~2021/12/31总销量之和,一个固定的值。
度量值3 = calculate([总销售],FILTER(all('日期表'),'日期表'[Date]<=max('日期表'[Date]) && '日期表'[年]=2021))
// 度量值3:在《DAX神功》第2卷第3回讲移动平均时介绍过他可以实现累积。本案例得到2021年月累积。
度量值4 = calculate([总销售],FILTER(all('日期表'[Date]),'日期表'[Date]<=max('日期表'[Date]) && year('日期表'[Date])=2021))
// 度量值4:度量值3限制日期表所有列,而度量值4限制日期表[Date]列,在本案例上效果是相同的。在《DAX神功》第2卷第3回也详细介绍过二者的应用环境。得到2021年月累积。

以上只是利用平移的方式,让你理解时间智能计算的过程,后续使用时间智能函数会简单很多
五、回答网友问题
关于《The Definitive Guide to DAX》中有一个类似的度量值:
度量值5 =
CALCULATE(
CALCULATE(
[总销售],
'日期表'[Date]>=date(2021,1,1) && '日期表'[Date]<=date(2021,12,31),
all('日期表')
),
'日期表'[年]=2021
)
这就是我常说的,不要轻易说人家对或错!
书中只是想讲一个道理,举出这样一个案例。
事实上你用不到这样的写法:
《DAX神功》第1卷第18回 孙兴华说:Calculate计值顺序和其它DAX函数一样,是从内向外的。内层已经指定了从2021/1/1至2021/12/31,为何还要在外层筛选2021年?
书中要表达的意思是:度量值3和度量值4算的是每个月的累积是通过平移的方法计算的,现在如果算指定年和指定月份区间求累积,你用平移的方法实现起来就不容易了,但是后面要讲的时间智能日期函数就非常简单了。这就是卖课人常说的,取新的范围:

六、网友对Calculate计值顺序的争议
因为刚刚提到了Calculate计值顺序,所以这里就再说一下。
声明:我从不证明谁对谁错!我只是证明路不只一条!(有争议的内容我可以摆出来让大家自己去鉴定,但从不下结论)
例如,一个国家花钱买装备要比研发装备省钱,但是为什么还要研发装备?这个道理大家都懂。数据分析,并不能从网上照搬案例,有一些程序员都可能从某些社区通过搜索,查到一些现成代码进行修改,但是分析不行,你的分析和人家的不一样,如果通过"借鉴"书籍或国外文献就能搞定,那可能不需要学习DAX,Excel工作表函数一定可以搞定,也许还更简单。
例如,有网友提出这样问题

网友提问时,文字说明:


我在《DAX神功》第1卷第18回,并没有说《The Definitive Guide to DAX》中说的不对,而是白纸黑字跟大家讲,路不只一条,我们思路不同,就好比去一个地方,路线不同,但是终点一样。
如同:有些人说编程英语比逻辑重要,其实谁重要都无所谓,能把代码写出来,正确运行才是王道。
关于我提出的,所有DAX函数都是从内向外计值顺序,我举证:以下图为例

VAR x='Sheet1'[Name] //指当前行的Name字段值
从内向外,先看内层,内层Calculate指的是A,B,C,D,E每个Name的Score值,新建列逐行迭代将ABCDE对应的值写在每一行。(如果A有2行,第1次出现时Score是73,第2次是1,那A对应的值都是74)
内层已经完成了每个值的分配任务,外层再写all(表)对我度量值本身无影响。
证明:
如果公式写成: Calculate(sum('Sheet1'[Score]),all(表)) // 返回ABCDE所有Name的Score值总和(一个固定值)
Calculate第一参数,是对[Score]列的聚合。
可是,我们现在的度量值,外层的Calculate第一参数生成新的列,你并没有对新列进行重新聚合。

换句话说,你并没有将 新列中的 73+97+55+99+59 sum在一起,关于score这列的聚合,内层calculate已经完成了他的使命,将值分配给每个Name了,这个时候再all(表)已经无意义了,因为筛选完毕了,结果生成了,再去取消表的筛选不会影响这个度量值。
无论是《The Definitive Guide to DAX》提出的从外向内,还是我提出的从内向外,最终我们结果是一致的。
其实,你细品,从外向内的说法,外层all(表),内层筛选这张表,当然原理是重新筛选,但是说出来同样很牵强。

在接下来的几节课中,我们将开始时间智能日期函数之旅!

《孙兴华讲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等等
https://www.bilibili.com/read/cv10222110