首先:忘记触发器。触发器不好
这是关于我通常如何执行此操作的脑筋急转弯。对此有很多排列,但这应该会给您一个想法。
这是目标维度中的一行。当然还有很多其他的行
| 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 是连接事实的键,在维度表中是唯一的(应通过约束或索引强制执行)
-
SourceKey是源系统中的key
-
SourceSystem 是提供此记录的任何系统的代码。
-
SourceKey + SourceSystem 是唯一的(应通过约束或索引强制执行)
我们将数据加载到我们的数据仓库中。通常,第一步是将输入数据加载到临时表中。所以假设我们在临时表中有这个:
| EmpKey |
EmpName |
EmpCity |
ActiveRecordSurrogateKey |
Ignore |
| 52 |
John |
Amsterdam |
NULL |
NULL |
| 73 |
Jim |
Brisbane |
NULL |
NULL |
| 7 |
Jack |
Texas |
NULL |
NULL |
ActiveRecord 和 Ignore 是工作列,它们不是来自源代码。其他所有列确实来自源,但对维度一无所知
维度和staging表中显然会有很多记录。
首先排除维度中所有最新的记录。
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 |
EmpName |
EmpCity |
ActiveRecordSurrogateKey |
Ignore |
| 52 |
John |
Amsterdam |
NULL |
NULL |
| 73 |
Jim |
Brisbane |
NULL |
Y |
| 7 |
Jack |
Texas |
NULL |
NULL |
标识暂存表中维度中已有活动记录但属性不同的所有记录
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 |
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
存储过程比较源(暂存)和目标(维度)并做所有正确的事情。
还有很多其他的事情需要考虑,但这会给你一个想法。