我在mssql服务器上有两个表,可以通过自定义的insert/update/delete和Merge语句执行scd。
Awesome Merge
我想知道有没有什么通用的程序可以达到这个目的。我们只要给它递两张桌子,它就会把SCD打印出来。SQL server 2008中有任何选项吗?
谢谢
最佳答案
不,没有也不可能有一个通用的,不管你传递给它的是什么表。有几个原因:
你怎么知道哪种类型的SCD?(好吧,可能是另一个参数,但是…)
你怎么知道哪些列应该被历史化,哪些应该被重写?
如何确定哪个列是业务键、代理项键、过期列等?
要在update语句中指定列,您必须编写动态sql,这是可能的,但上面这一点起作用了
这不是不可能的原因,但也要考虑:对于一个正常的UPSERT
语句,它通常与临时表一起工作,MERGE
语句对于scd很糟糕,除非在特殊情况下。这是因为您不能将MERGE
语句与INSERT/UPDATE
语句一起使用,并且您必须为此禁用外键,因为UPDATE
被实现为DELETE THEN INSERT
(或者类似的东西,不清楚地记得,但我在尝试时遇到了这些问题)。
我更喜欢这样做(SCD类型2和SQL Server即):
步骤1:
IF EXISTS (
SELECT * FROM sys.objects
WHERE name = 'tmpDimSource')
DROP TABLE tmpDimSource;
SELECT
*
INTO tmpDimSource
FROM
(
SELECT whatever
FROM yourTable
);
步骤2:
IF EXISTS (
SELECT * FROM sys.objects
WHERE name = 'tmpDimYourDimensionName')
DROP TABLE tmpDimYourDimensionName;
SELECT * INTO tmpDimYourDimensionName FROM D_yourDimensionName WHERE 1 = 0;
INSERT INTO tmpDimYourDimensionName
(
sid, /*a surrogate id column*/
theColumnsYouNeedInYourDimension,
validFrom
)
SELECT
ISNULL(d.sid, 0),
ds.theColumnsYouNeedInYourDimension,
DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()), 0) /*the current date*/
FROM
tmpDimSource ds
LEFT JOIN D_yourDimensionName d ON ds.whateverId = c.whateverId
;
步骤2中的
ISNULL(d.sid, 0)
很重要。它返回维度的代理ID,如果条目已经存在,则为0。步骤3:
UPDATE D_yourDimensionName SET
validTo = DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()) - 1, 0) /*yesterday*/
FROM
D_yourDimensionName d
INNER JOIN tmpDimYourDimensionName t ON d.sid = t.sid
WHERE t.sid <> 0 AND
(
d.theColumnWhichHasChangedAndIsImportant <> t.theColumnWhichHasChangedAndIsImportant OR
d.anotherColumn <> t.anotherColumn
)
;
在步骤3中,标记现有的条目不再有效,并保留它的历史记录。使用
WHERE validTo IS NULL
获得的有效条目。如果需要,还可以添加另一个
UPDATE
以用新值覆盖任何其他列。步骤4:
INSERT INTO D_yourDimensionName
SELECT * FROM tmpDimYourDimensionName
WHERE sid = 0;
就这样。