简体   繁体   English

插入历史记录表并根据表内容选择有效日期和有效日期

[英]Insert into history table and selecting validFrom and validTo dates based on table contents

Edit: Using SQL-Server 2008 编辑:使用SQL Server 2008

I have an AccountHistory table that has multiple columns. 我有一个AccountHistory表,其中包含多个列。 Relevant for this case is Account_FK, ValidTo, ValidFrom 与这种情况有关的是Account_FK,ValidTo,ValidFrom

Im trying to insert new values into this table by using: 我正在尝试使用以下方法将新值插入此表:

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

Problem is: If there is an existing row with the same Account_FK in AccountHistory, the inserted row should have its ValidFrom date set to current date. 问题是:如果在AccountHistory中存在具有相同Account_FK的现有行,则插入的行应将其ValidFrom日期设置为当前日期。 ValidTo should be null. ValidTo应该为null。 And the old AccountHistory-row should have its ValidTo date updated from null to current date. 并且旧的AccountHistory行应该将其ValidTo日期从null更新为当前日期。 If there is no other row with the same Account_FK then the validFrom date should be set to a system-default start date, eg 1990-01-01 如果没有其他具有相同Account_FK的行,则应该将validFrom日期设置为系统默认的开始日期,例如1990-01-01

How is this most easily and elegantly solved? 如何最轻松,最优雅地解决这个问题? I know a trigger might be the thing, but if there is a better way then i would like to hear your suggestions. 我知道可能是触发因素,但是如果有更好的方法,那么我想听听您的建议。

ValidFrom field is a not null field so i cant insert any null into it. ValidFrom字段是一个非null字段,因此我无法在其中插入任何null。

If using 2008 you can use the merge statement - Solutions for INSERT OR UPDATE on SQL Server - see Keith's answer about a third of the way down. 如果使用2008,则可以使用merge语句-SQL Server上INSERT或UPDATE的解决方案 -请参阅Keith的答案,大约三分之一。 Would that work? 那行得通吗?

The simplest answer is to remove the ValidTo field, which is effectively a derived field (which you're usually not supposed to store). 最简单的答案是删除ValidTo字段,该字段实际上是派生字段( 通常不应该存储)。 Then, you only have to insert the relevant entries, and can derive the needed value fairly trivially (requires aggregated self-join). 然后,您只需插入相关条目,即可相当轻松地得出所需的值(需要聚合的自联接)。

However, I'm a little concerned that you're overriding the given ValidFrom date if an entry exists - you're effectively making it impossible to back-date history, and that new entries will always be 'new, and currently in effect', which is extremely unlikely. 但是,我有点担心如果条目存在,您将覆盖给定的ValidFrom日期-您实际上无法回溯历史记录,并且新条目将始终是“新的且当前有效” ,这是极不可能的。 For one thing, if you ever insert multiple entries, you may not have a garuanteed insert order, which will promptly play havoc with this. 一方面,如果您插入多个条目,则可能没有合适的插入顺序,这将立即对此造成破坏。 It also makes it impossible to back-date entries, if necessary (note: this isn't necessarily for nefarious purposes - there are occasionally good business reasons to backdate 'eligible' history. Include an entry timestamp, for auditing, though). 如果需要的话,这也使得不可能对条目进行回溯(请注意:这不一定是出于邪恶目的-有时出于良好的商业原因,必须对“符合条件的”历史进行回溯。不过,包括用于审核的条目时间戳记)。 Also, what happens when you have multiple entries for the same day - how would you know which one was correct (so are you sure you don't actually want a timestamp)? 此外,当同一天有多个条目时会发生什么-您怎么知道哪一个是正确的(因此您确定实际上并不需要时间戳)?

Other than that, here's the two statements (tested on DB2) I would use to modify the table as you described. 除此之外,这是我用来修改表的两条语句(在DB2上进行了测试)。
First, an insert statement to take care of the new entries: 首先,使用一条插入语句来处理新条目:

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

And an update statement to populate 'ValidTo' dates (this gets everything, not just what was inserted): 还有一条用于填充“ 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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM