仅按日期缓慢改变维度

Posted

技术标签:

【中文标题】仅按日期缓慢改变维度【英文标题】:Slowly changing dimension by date only 【发布时间】:2014-12-11 08:29:19 【问题描述】:

我有一个数据库表,它使用渐变维度的数据仓库概念来跟踪旧版本。 所以,我用Log Trigger机制实现了它。

我的桌子是这样的:

CREATE TABLE "T_MyTable" (
    "Id" INT NOT NULL DEFAULT NULL,
    "Description" NVARCHAR(255) NULL DEFAULT NULL )

我创建了一个 hystory 表

CREATE TABLE "T_MyTableHistory" (
    "Id" INT NOT NULL DEFAULT NULL,
    "Description" NVARCHAR(255) NULL DEFAULT NULL,
    StartDate DATETIME,
    EndDate   DATETIME )

然后,通过这样的触发器,我得到了历史记录:

CREATE TRIGGER TableTrigger ON T_MyTable FOR DELETE, INSERT, UPDATE AS

DECLARE @NOW DATETIME
SET @NOW = CURRENT_TIMESTAMP

UPDATE T_MyTableHistory
   SET EndDate = @now
  FROM T_MyTableHistory, DELETED
 WHERE T_MyTableHistory.Id = DELETED.Id
   AND T_MyTableHistory.EndDate IS NULL

INSERT INTO T_MyTableHistory (Id, Description, StartDate, EndDate)
SELECT Id, Description, @NOW, NULL
  FROM INSERTED

而且,为了查询历史表,我使用

SELECT  Id, Description
    FROM T_MyTableHistory
    WHERE @DATE >= StartDate
    AND (@DATE < EndDate OR EndDate IS NULL)

现在,我的问题是:我的客户实际上会按 date only(即没有一天中的时间)查询历史记录表,因此我需要获取该日期的记录版本。 我想了两个选择:

    将触发器(如何?)更改为每个日期只记录一个“历史”记录。

    保持触发器不变,记录数据库中的所有变化(包括日期和时间),然后查询历史表以获取特定日期的最新版本(如何?)

我的感觉是第二个选项更容易实现,否则触发器可能会变得复杂(插入或更新,取决于当前日期的历史记录的存在)。

在选择正确的方向时我需要一些帮助,并且我想在所选选项中提供所需的 SQL 查询示例。

【问题讨论】:

【参考方案1】:

我同意您的第二意见。 最好将日期与时间一起保存。根据日期使用过滤数据时 CONVERT() 函数确保仅比较 DATE。此外,当客户输入单个日期时,如果记录具有相同的开始日期和结束日期 它们不会出现在您的过滤器中,因此使用 Date >= StartDate 和 Date = ,

DECLARE @Date AS DATETIME
SET @Date = '2013-07-30'

SELECT TOP 1 Id, Description
    FROM T_MyTableHistory
    WHERE CONVERT(VARCHAR(20), @DATE, 103) 
       >= CONVERT(VARCHAR(20), StartDate, 103)
    AND (CONVERT(VARCHAR(20), @DATE, 103) 
       < CONVERT(VARCHAR(20), EndDate, 103) OR EndDate IS NULL)
    ORDER BY StartDate DESC

【讨论】:

感谢您的回答。实际上,如果我在同一天(不同时间)有多个版本,通过您的查询,我会收到许多相同 ID 的记录,对吗?我想要的是在指定日期有效的最新记录。 简单,第一条记录使用TOP 1,数据排序使用ORDER BY StartDate DESC。试试我更新的答案。【参考方案2】:

最后,我想出了这个查询:

SELECT Id, Description
    FROM T_MyTableHistory
    WHERE ( DateAdd(day, datediff(day,0, @MyDate), 0) >= StartDate ) AND 
    (( DateAdd(day, datediff(day,0, @MyDate), 0) < EndDate ) OR ( EndDate IS NULL ))

这应该比 varchardatetime 转换更快,并且它也应该与语言环境无关。 顺便说一句,这个查询不需要TOP 1ORDER BY 子句,因为函数

DateAdd(day, datediff(day,0, @MyDate)

自动返回所选日期,带有“午夜”时间(例如 20141215 00:00:00),因此具有相同日期的记录会自动从结果中剔除。

参考资料:

How to return the date part only from a SQL Server datetime datatype

Best approach to remove time part of datetime in SQL Server

【讨论】:

以上是关于仅按日期缓慢改变维度的主要内容,如果未能解决你的问题,请参考以下文章

维度建模创建/修改日期/人

kettle学习之--缓慢变化维度(SCD)

HIVE- SCD缓慢变化

关于缓慢变化维

一致性维度也可以是一个缓慢变化的维度吗?

聊聊数据仓库中的缓慢变化维度(SCD)