SQL数据仓库和Tableau中的时间表和时间维

问题描述

我正处于重新设计数据仓库的开始阶段,发现时态表是处理SCD类型4的绝妙方法。此数据仓库的迭代将具有日期维度,因此我们可以转到时间点使用业务逻辑进行比较(例如,比较会计季度中的特定日期)。日期维度将具有各种很酷的业务时间标记,例如会计年度/季度/月和月/季度/年中的天,以及各种其他开始日期和结束日期标记,这些信号指示不同的业务流程和“季节”。

我看到的唯一问题是,我看不到如何在不始终使用单独的日期字段并将查询执行为'for system_time all'的情况下利用查询中的日期维度。这是因为您实际上无法对'for system_time'语句之后的日期进行任何操作。

现在,我了解到您可以看到日期是一个变量,并且可以在设置变量时进行操作。我的问题是Tableau不允许您执行sql脚本(如power BI一样),而只能执行单个语句。因此,我无法实现根据查询结果将日期设置为变量的情况。因此,我不确定如何运行时间查询以说让我们获取特定会计季度的特定日期的值。希望有道理。

如果我必须使用触发器手动创建历史记录表,那么我认为还有一个更好的解决方案,我的Google搜索尚未找到。您能指出我任何想法或文章吗?


编辑添加示例:

例如,假设我们有一个日期维度(dateTable),其中包含几个字段:

date
fiscalYear
fiscalDayOfYear

现在假设我有一个包含几个字段的表(statusTable):

userid
status
date (FK to date dimension)

现在让我们说我想在2019和2020财年的第20天比较特定的用户状态。如果不使用时态表,它将看起来像:

select st.userid,st.status from statusTable st inner join dateTable dt on st.date = dt.date where dt.fiscalDayOfYear = '20' AND (dt.fiscalYear = '2020' or dt.fiscalYear = '2019')

现在,如果statusTable是一个临时表,它将看起来像这样:

userid
status
systemtimeFrom (generated by temporal table)
systemtimeto (generated by temporal table)

在上面的查询中,我如何处理时间表?除了系统时间字段外,我还看到了人们在状态表中添加“日期”字段的示例。它们具有自动生成的价值。因此,从理论上讲,我可以像上面的查询一样加入。但是,我看到的问题是,如果查询没有时间约束的时间表,它将仅查看最新状态(因为这就是表中的全部内容)。如果我想包括历史记录和当前表,我想我需要做一个包含“ FOR SYstem_TIME ALL”的选择,我觉得这消除了时态表的好处(因为您不能在很酷的时间内对时态查询进行切片) )。

我要查找的内容是,是否有一种方法可以使用我不知道的某种魔术对临时表进行上述查询。我希望能够做类似的事情(而且我知道这不是有效的sql,因为您只能在as of子句中提供日期或变量):

select st.userid,st.status from statusTablest st for system_time as of (select date from datetable where dt.fiscalDayOfYear = '20' AND (dt.fiscalYear = '2020' or dt.fiscalYear = '2019'))

对不起,我知道这不是一个很好的例子。我没有太多示例,因为我是从头开始设计的。我希望我能尽我所能。让我知道是否可以,我可以尝试用其他方式说出来。

解决方法

感谢示例和其他信息。我意识到,尝试为此类问题提供一个真实的示例绝非易事,但我需要指出的是,您的示例与维模型不兼容,因为您永远不会像这样将维连接在一起并使用一个维过滤另一个-维度已连接到事实表并用于过滤事实表。

但是,请注意,请看一下您的示例...

您显示的非时态表将不支持您要运行的查询类型,因为它可能需要为您要查询的每个日期/用户/状态组合提供一条记录-这显然是不支持的。相反,您将需要有效的开始日期和结束日期来显示适用于每种用户名和状态组合的日期期限。如果您有这些日期,那么您的查询可能看起来像这样(未经测试的示例,因为我没有数据可以运行):

select st.userid,st.status,st.ValidFrom,st.ValidTo 
from statusTable st 
inner join dateTable dt1 on st.ValidFrom = dt1.date 
inner join dateTable dt2 on st.ValidTo = dt2.date 
where 
(dt1.fiscalDayOfYear <= '20' AND dt2.fiscalDayOfYear >= '20') -- your fiscal day is within the coverage of the statusTable record
AND
(dt1.fiscalYear = '2020' or dt1.fiscalYear = '2019') -- limit to the 2 years in question
AND
(dt1.fiscalYear = dt2.fiscalYear); -- Attempt to filter to a single record.Probably incorrect if the ValidFrom and ValidTo dates for a record are in different years; required logic more complex than this 

因此,您基本上必须具有SCD2类型的表才能运行这些类型的查询。

时间表还具有ValidFrom和ValidTo列-因此,它与传统的SCD2表基本相同;区别在于必须使用ETL逻辑维护SCD2表,而临时表由数据库引擎自动维护。

查询SCD2表和等效时间表的逻辑几乎是相同的。主要区别是使用

FOR SYSTEM_TIME ...

子句-但是,所有要做的就是从查询中使用的statusTable数据子集中,并且要做到这一点,您将需要构造合适的开始日期和结束日期参数并将其传递给查询。如果您无法执行此操作(或者时间段太长,以至于产生子集不太可能使查询受益),则只需使用:

FOR SYSTEM_TIME ALL

因此,希望澄清/回答您提出的一些观点:

  • 临时表是一种自动存储历史记录的方法,而不必手动维护SCD2表-但最终结果实际上是相同的
  • 您的语句“ 我想我需要做一个包含'FOR SYSTEM_TIME ALL'的选择,我觉得这消除了时态表的好处(因为您不能在很酷的时间内对时态查询进行切片)。 / em>“表示对时间表的点可能存在的误解。它们的好处是它们会自动保存历史记录,并允许您查询历史记录。日期时间而不是时间表启用了“ 最酷的时间切片时间查询”功能,因此,您仍然需要将时间表与日期维度结合起来,才能使其正常工作