我在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;

就这样。

09-26 21:28