DAX Patterns | 关于时间的标准计算
关于这个模式
在这个模式中,我们将向你展示如何使用标准日历计算与时间相关的计算,如年初至今、去年同期和百分比增长。使用标准日历的最大优点是:你可以依赖多个内置的时间智能函数。内置函数的设计方式是为最常见的需求提供正确的结果。
如果内置函数无法满足你的需求,或者你正在使用一个非标准的日历,那么你应该使用常规的(与时间无关的)DAX函数来达到相同的目标。通过这种方式,你可以随意定制代码的结果。也就是说,如果你需要自定义计算,那么还需要使用一组列来丰富你的日期表,这些列将被DAX公式用于移动筛选器。这些自定义计算将在自定义时间相关的计算模式中进行介绍。
如果你使用的是常规的公历,那么此模式中的公式是产生时间智能计算的最简单和最有效的方法。请记住,标准的DAX时间智能函数只支持常规的公历——即一年由12月组成,每个月包含它的公历天数(28~31天),三个月组成一个季度,以及我们所习惯的日历的所有常规方面。
介绍时间智能计算
为了使用任何时间智能计算,你需要一个格式良好的日期表。日期表必须满足以下要求:
包含所需年份的所有日期。日期表必须从1月1日开始,到12月31日结束,并包含这个范围内的所有天数。如果报告只引用财年,那么日期表必须包括从财年的第一天到最后一天的所有日期。例如:如果2008财年从2007年7月1日开始,那么日期表必须包含从2007年7月1日到2008年6月30日的所有天数。
需要有一个具有DateTime 或Date 数据类型并且包含唯一值的列。通常这一列命名为Date。虽然Date 列经常被用于定义与其他表之间的关系,但这不是必需的。尽管如此,Date 列必须包含唯一的值,并且应该由“标记为日期表”特性引用。如果该列还包含时间部分,则不应该使用时间——例如,时间应该始终是12:00 am。
Date 表必须在模型中标记为日期表,以防Date 表和其他表之间的关系(例如示例中的Sales 表)不是基于日期列。
有几种不同方法可以构建Date 表。只要日期表满足以上要求,构建Date 表的方式并不影响使用标准时间智能计算的方式。如果你已经有一个适用于你的报告的Date 表,只需导入它并在检查它满足最低要求之后将其标记为日期表。如果你没有Date 表,可以使用稍后描述的DAX计算表创建一个。
最佳实践是: 将用于时间智能计算的Date 表标记为日期表。每次在Date 列上应用一个筛选器时,'标记为日期表'设置都会对日期表自动添加REMOVEFILTERS。这个操作(在Date列上应用一个筛选器)是由作为CALCULATE的筛选参数的时间智能函数执行。如果你使用Date 列定义了Sales 和Date 之间的关系,DAX会表现出相同的行为。尽管如此,将'标记为日期表'设置应用于日期表是一个最佳实践。如果你有多个日期表,你可以将所有日期表标记为日期表。
如果没有使用'标记为日期表'设置并且没有使用日期列定义关系,那么每当在CALCULATE中使用时间智能函数时,都必须对日期表添加REMOVEFILTERS。关于这个行为的更多细节请浏览Power BI Desktop中的时间智能。
什么是标准的DAX时间智能函数?
标准的时间智能函数是表函数,它返回一列用于作为CALCULATE的筛选参数的日期值。可以通过编写一个比较复杂的筛选表达式来获得和时间智能函数相同的结果。例如,DATESYTD 函数返回从同一年中的第一天到当前筛选上下文中可见的最后一天之间的所有日期。
等同于下面的FILTER表达式:
有很多时间智能函数,我们将在这个模式中呈现它们中的大部分。请注意:时间智能函数应该作为CALCULATE的筛选参数,并且有时你将借助变量来实现这一点。在迭代函数中使用时间智能函数是危险的,因为会触发隐式的上下文转换, 并且从转换而来的筛选上下文中检索可见的日期。关于这个行为的更多细节请浏览DAX Guide文档: https://dax.guide/datesytd/。
以下是使用时间智能函数的最佳实践的快速指南:
仅在CALCULATE / CALCULATETABLE的筛选器参数中使用像DATESYTD这样的时间智能函数,或者使用时间智能函数将筛选器分配于变量。
在返回值的DAX表达式中使用标量函数—也称为标量表达式,如EDATE和EOMONTH。这些函数不是时间智能函数,可以在行上下文中计值的表达式中使用。
使用CONVERT将日期转换为数字,反之亦然。
请浏览https://dax.guide/获得有关时间智能函数的最新完整清单。
DAX初学者经常混淆时间智能函数和正则标量时间函数。这种混淆会导致一些常见的错误,可以通过遵循以下建议来避免:
不要使用DATEADD返回前一天或第二天,你可以使用简单的数学运算符实现。
不要在标量表达式中使用PREVIOUSDAY计算前一天。你只需从日期上减去一天,就可以在标量表达式中获取前一天。
不要使用EOMONTH作为筛选器参数,而要使用ENDOFMONTH 。EOMONTH是一个标量表达式。ENDOFMONTH是一个时间智能函数。始终要注意函数的返回类型:只有表函数是时间智能函数,并且不应该在标量表达式中使用时间智能函数。
禁用自动日期/时间
Power BI自动为模型中的每个日期或日期时间类型的列创建一个日期表。然而, 我们
我们强烈建议禁用Power BI自动创建的日期表,并取而代之,导入或创建一个显式的日期表。关于这一建议的更多细节请浏览文章Automatic time intelligence in Power BI。
自动日期表的存在还启用了一种被称为列变体的特殊语法。它表现为: 在日期列后有一个点,后面再跟着一个自动创建的日期表中的列。
当对一个自动日期表使用Power BI快速度量值时, Power BI快速度量值大量使用了列变体。我们不依赖于在Power BI中自动创建的日期表,因为我们希望对模型保持最大的灵活性和最大的控制。列变体的语法不支持作为模型一部分的日期表,因此,也不能自动创建。
标准时间智能函数的局限性
标准时间智能函数适用于常规的公历。在本章节中列出了它们的几个限制。当你的需求和这些限制不兼容时,你需要另外的模式(请参阅 Custom time-related calculations 和 Week-related calculations)。
年从1月1日开始。对于从一个不同日期开始的财年日历的支持有限。而且,每个财年的第一天必须是同一天并且由于与闰年有关的历史bug不能是3月1日。
季度总是在1月、4月、7月和10月的第一天开始。一个季度的日期范围不能被修改。
月总是一个日历月
标准时间智能函数可能无法正确地筛选附加列,例如Day of Week或Working Day。关于可能的解决方案的更多细节,将在本章后面的'筛选其他日期属性'中介绍。
因此,标准时间智能计算不支持许多高级计算,比如对于周的计算。这些高级计算需要自定义日历。