首先:忘记触发器。触发器不好
这是关于我通常如何执行此操作的脑筋急转弯。对此有很多排列,但这应该给你一个想法。
这是目标维度中的一行。当然还有很多其他的行
代理键 |
源密钥 |
源系统 |
企业名称 |
空城 |
DWHDatStart |
DWHDatEnd |
活跃 |
3678 |
52 |
人力资源系统1 |
约翰 |
伦敦 |
2020-02-20 |
9999-12-31 |
是 |
3642 |
73 |
人力资源系统1 |
吉姆 |
布里斯班 |
2021-03-18 |
9999-12-31 |
是 |
SurrogateKey
是连接到您的事实的键并且在维度表中是唯一的(并且应该使用约束或索引强制执行)
SourceKey
是源系统中的key
SourceSystem
是提供此记录的任何系统的代码。
SourceKey
+SourceSystem
是唯一的(并且应该使用约束或索引强制执行)
我们将数据加载到我们的数据仓库中。通常,第一步是将输入数据加载到临时表中。所以说我们在临时表中有这个:
EmpKey |
企业名称 |
空城 |
ActiveRecordSurrogateKey |
忽视 |
52 |
约翰 |
阿姆斯特丹 |
无效的 |
无效的 |
73 |
吉姆 |
布里斯班 |
无效的 |
无效的 |
7 |
杰克 |
德克萨斯州 |
无效的 |
无效的 |
ActiveRecord
并且Ignore
是工作列,它们不是来自源头。其他所有列确实来自源,但对维度一无所知
维度和临时表中显然会有很多记录。
首先排除维度中所有最新的记录。
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'
我们已经确定 Jim 没有改变,可以忽略
EmpKey |
企业名称 |
空城 |
ActiveRecordSurrogateKey |
忽视 |
52 |
约翰 |
阿姆斯特丹 |
无效的 |
无效的 |
73 |
吉姆 |
布里斯班 |
无效的 |
是 |
7 |
杰克 |
德克萨斯州 |
无效的 |
无效的 |
标识暂存表中在维度中已有活动记录但具有不同属性的所有记录
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)
(如果您愿意,这两个单独的更新可以合并为一个。)
现在我们的临时表看起来像这样。
EmpKey |
企业名称 |
空城 |
ActiveRecordSurrogateKey |
忽视 |
52 |
约翰 |
阿姆斯特丹 |
3678 |
无效的 |
73 |
吉姆 |
布里斯班 |
无效的 |
是 |
7 |
杰克 |
德克萨斯州 |
无效的 |
无效的 |
现在我们有足够的信息来更新维度。我们可以根据辅助列编写更多的 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
现在我们的维度看起来像这样
代理键 |
源密钥 |
源系统 |
企业名称 |
空城 |
DWHDatStart |
DWHDatEnd |
活跃 |
3678 |
52 |
人力资源系统1 |
约翰 |
伦敦 |
2020-02-20 |
9999-12-31 |
是 |
3642 |
73 |
人力资源系统1 |
吉姆 |
布里斯班 |
2021-03-18 |
9999-12-31 |
是 |
3693 |
7 |
人力资源系统1 |
杰克 |
德克萨斯州 |
2021-06-09 |
9999-12-31 |
是 |
3694 |
52 |
人力资源系统1 |
约翰 |
阿姆斯特丹 |
2021-06-09 |
9999-12-31 |
是 |
现在我们结束现有记录的日期:
-- This line end-dates existing records:
UPDATE DimensionTable
SET DWEndDate = @Date, Active = 'N'
FROM DimensionTable TGT
INNER JOIN StagingTable SRC
ON TGT.SurrogateKey = ActiveRecordSurrogateKey
代理键 |
源密钥 |
源系统 |
企业名称 |
空城 |
DWHDatStart |
DWHDatEnd |
活跃 |
3678 |
52 |
人力资源系统1 |
约翰 |
伦敦 |
2020-02-20 |
2021-06-09 |
ñ |
3642 |
73 |
人力资源系统1 |
吉姆 |
布里斯班 |
2021-03-18 |
9999-12-31 |
是 |
3693 |
52 |
人力资源系统1 |
杰克 |
德克萨斯州 |
2021-06-09 |
9999-12-31 |
是 |
3694 |
52 |
人力资源系统1 |
约翰 |
阿姆斯特丹 |
2021-06-09 |
9999-12-31 |
是 |
因此,您基本上将所有这些 T-SQL 语句包装在一个存储过程中,添加一些事务、日志记录和错误处理。
CREATE PROC pUpdateDimPerson
AS
BEGIN
-- All the code above
END
存储过程比较源(暂存)和目标(维度)并做所有正确的事情。
还有很多其他的事情需要考虑,但这会给你一个想法。