插入历史表并根据表内容选择validFrom和validTo日期

时间:2011-11-30 15:40:38

标签: sql sql-server tsql

编辑:使用SQL-Server 2008

我有一个包含多列的AccountHistory表。与此案例相关的是Account_FK,ValidTo,ValidFrom

我尝试使用以下方法将新值插入此表:

INSERT INTO AccountHistory (Account_FK, ValidTo, ValidFrom)
SELECT Account_FK, ValidTo, ValidFrom
FROM someOtherTable

问题是: 如果AccountHistory中存在具有相同Account_FK的现有行,则插入的行应将其ValidFrom日期设置为当前日期。 ValidTo应为null。旧的AccountHistory-row应将其ValidTo日期从null更新为当前日期。 如果没有其他具有相同Account_FK的行,则validFrom日期应设置为系统默认开始日期,例如1990-01-01

这是如何最容易和优雅地解决的?我知道触发器可能是事情,但如果有更好的方法,那么我想听听你的建议。

ValidFrom字段是一个非空字段,因此我无法在其中插入任何null。

2 个答案:

答案 0 :(得分:0)

如果使用2008,您可以使用合并声明 - Solutions for INSERT OR UPDATE on SQL Server - 请参阅Keith关于三分之一的答案。那会有用吗?

答案 1 :(得分:0)

最简单的答案是删除ValidTo字段,该字段实际上是派生的字段(您通常不应存储)。然后,您只需要插入相关条目,并且可以相当简单地导出所需的值(需要聚合的自连接)。

但是,我有点担心如果条目存在,你将覆盖给定的ValidFrom日期 - 你实际上是无法回溯历史记录,并且新条目将永远是'新的,现在有效的,这是极不可能的。首先,如果您插入多个条目,可能不会有一个附加的插入订单,这将立即对此进行破坏。如果有必要,这也使得无法更新条目(请注意:这不一定是出于恶意目的 - 有时候有良好的商业理由来回溯“符合条件的”历史记录。但是,包括入境时间戳,用于审计)。此外,当你在同一天有多个条目时会发生什么 - 你怎么知道哪一个是正确的(所以你确定你真的不想要时间戳)?

除此之外,这里是两个语句(在DB2上测试)我会用你来修改表格。
首先,使用insert语句来处理新条目:

INSERT INTO AccountHistory (Account_FK, ValidTo, ValidFrom)
SELECT a.Account_FK, CASE WHEN b.Account_FK IS NULL 
                          THEN a.ValidTo
                          ELSE NULL END,
                     CASE WHEN b.Account_FK IS NULL
                          THEN a.ValidFrom
                          ELSE CURRENT_DATE END
FROM SomeOtherTable as a
LEFT JOIN (SELECT DISTINCT Account_FK
           FROM AccountHistory) as b
ON b.Account_FK = a.Account_FK

用于填充'ValidTo'日期的更新语句(这会获取所有内容,而不仅仅是插入的内容):

UPDATE AccountHistory as a SET ValidTo = (SELECT MIN(b.ValidFrom)
                                          FROM AccountHistory as b
                                          WHERE a.Account_FK = b.Account_FK
                                          AND b.ValidFrom > a.ValidFrom)
WHERE ValidTo IS NULL
AND EXISTS (SELECT '1'
            FROM AccountHistory as b
            WHERE a.Account_FK = b.Account_FK
            AND b.ValidFrom > a.ValidFrom)