在单个 table 中使用 TSQL 脚本更改 tracking/history 保留在 SQL 数据库中

Change tracking/history keeping in SQL database using TSQL script in single table

对于上下文,我有一个简单的 Azure SQL 数据库,我有一个理论维度模型,其中包含 12 个维度和一些最终应该作为 DWH 运行的事实 table。

我希望在此维度模型上应用历史化。为了简单起见并应用历史化的概念,我想在一个维度上启用它。在我的例子中,这是 DimEmployee,它看起来像这样,带有一行示例数据(它有更多的列,但为了简单起见,我只采用这些)

EmpKey 员工姓名 EmpCity DWHDatStart DWHDatEnd 有效
52 约翰 伦敦 02/02/2020 31/12/9999 Y

现在,如果假设 John 搬到另一个城市,我希望对此进行跟踪,那么更新 EmpCity 的值时所需的情况将是

EmpKey 员工姓名 EmpCity DWHDatStart DWHDatEnd 有效
52 约翰 阿姆斯特丹 2021 年 6 月 8 日 31/12/9999 Y
52 约翰 伦敦 02/02/2020 2021 年 6 月 8 日 N

我将如何在 TSQL 中应用它。我认为它必须是某种触发器,但缺乏应用它的具体知识。 我读过有关时间 tables 的信息,通常在对数据启用历史化时,您将历史数据存储在单独的历史记录 table 中。我认为由于这个模型设计,总是可以通过添加 DimEmployeeHist 维度或其他任何东西来扩展这个概念,但对于第一个概念,这是不需要的。我不知道单独 table 这样做会带来什么价值,除非你有很多历史记录,所以你希望它们全部整齐地存储在一个地方,以免弄乱你的主 table s.

这是否必须在创建 table 脚本中完成,还是可以在创建 table 之后完成?

首先:忘记触发器。触发器不好

这是关于我通常如何执行此操作的脑洞。对此有很多排列,但这应该会给你一个想法。

这是目标维度中的一行。当然还有很多其他行

SurrogateKey SourceKey SourceSystem EmpName EmpCity DWHDatStart DWHDatEnd IsActive
3678 52 HRSystem1 John London 2020-02-20 9999-12-31 Y
3642 73 HRSystem1 Jim Brisbane 2021-03-18 9999-12-31 Y
  • SurrogateKey 是连接到您的事实的键,并且在维度 table 中是唯一的(并且应该使用约束或索引来强制执行)
  • SourceKey是源系统中的key
  • SourceSystem 是提供此记录的任何系统的代码。
  • SourceKey + SourceSystem 是唯一的(应该用约束或索引强制执行)

我们将数据加载到我们的数据仓库中。通常第一步是将输入数据加载到分段 table。所以说我们在一个阶段 table:

EmpKey EmpName EmpCity ActiveRecordSurrogateKey Ignore
52 John Amsterdam NULL NULL
73 Jim Brisbane NULL NULL
7 Jack Texas NULL NULL

ActiveRecordIgnore 是工作专栏,它们不是来自源代码。其他每一列都来自源,但对维度一无所知

维度和分期显然会有很多记录table。

首先排除维度中所有最新的记录。

UPDATE StagingTable
SET Ignore = 'Y'
FROM StagingTable TGT
INNER JOIN DimensionTable SRC
ON TGT.EmpKey = SRC.SourceKey
AND TGT.SourceKey = 'HRSystem1'
AND TGT.EmpName=SRC.EmpName 
AND TGT.EmpCity=SRC.EmpCity
AND SRC.IsActive = 'Y'

我们确定吉姆没有改变,可以忽略

EmpKey EmpName EmpCity ActiveRecordSurrogateKey Ignore
52 John Amsterdam NULL NULL
73 Jim Brisbane NULL Y
7 Jack Texas NULL NULL

识别暂存中的所有记录table,这些记录在维度中已有活动记录但具有不同的属性

UPDATE StagingTable
SET ActiveRecordSurrogateKey = SRC.SurrogateKey
FROM StagingTable TGT
INNER JOIN DimensionTable SRC
ON TGT.EmpKey = SRC.SourceKey
AND TGT.SourceKey = 'HRSystem1'
AND TGT.IsActive='Y'
AND (TGT.EmpName<>SRC.EmpName OR TGT.EmpCity<>SRC.EmpCity)

(如果您愿意,可以将这两个单独的更新合并为一个。)

现在我们的舞台 table 看起来像这样。

EmpKey EmpName EmpCity ActiveRecordSurrogateKey Ignore
52 John Amsterdam 3678 NULL
73 Jim Brisbane NULL Y
7 Jack Texas NULL NULL

现在我们有足够的信息来更新维度。我们可以再写一些 SQL 以应用于基于辅助列的维度。

但首先,让我们指定一个固定日期。如果它在午夜前后运行,这将阻止奇怪的事情发生。或者您可能想通过其他方式确定这一点,例如源中的输入参数或数据

DECLARE @Date DATE = GETDATE();

现在我们可以插入所有新记录(全新的或更改的)

-- This line inserts new dimension records:
INSERT INTO DimensionTable (SourceKey,SourceSystem,EmpName,EmpCity, StartDate,EndDate,IsActive)
SELECT EmpKey,'HRSystem1',EmpName,EmpCity, @Date,'2999-01-01','Y' 
FROM StagingTable 
WHERE Ignore IS NULL

现在我们的维度看起来像这样

SurrogateKey SourceKey SourceSystem EmpName EmpCity DWHDatStart DWHDatEnd IsActive
3678 52 HRSystem1 John London 2020-02-20 9999-12-31 Y
3642 73 HRSystem1 Jim Brisbane 2021-03-18 9999-12-31 Y
3693 7 HRSystem1 Jack Texas 2021-06-09 9999-12-31 Y
3694 52 HRSystem1 John Amsterdam 2021-06-09 9999-12-31 Y

现在我们结束现有记录的日期:

-- This line end-dates existing records:
UPDATE DimensionTable
SET DWEndDate = @Date, Active = 'N'
FROM DimensionTable TGT
INNER JOIN StagingTable SRC
ON TGT.SurrogateKey  = ActiveRecordSurrogateKey
SurrogateKey SourceKey SourceSystem EmpName EmpCity DWHDatStart DWHDatEnd IsActive
3678 52 HRSystem1 John London 2020-02-20 2021-06-09 N
3642 73 HRSystem1 Jim Brisbane 2021-03-18 9999-12-31 Y
3693 52 HRSystem1 Jack Texas 2021-06-09 9999-12-31 Y
3694 52 HRSystem1 John Amsterdam 2021-06-09 9999-12-31 Y

所以您基本上将所有这些 T-SQL 语句包装在一个存储过程中,添加一些事务、日志记录和错误处理。

CREATE PROC pUpdateDimPerson
AS
BEGIN

-- All the code above

END

存储过程比较源(暂存)和目标(维度)并做所有正确的事情。

还有很多其他的事情需要考虑,但这给了你一个想法。