数据库 - 数据版本控制(后续)

时间:2009-05-25 22:47:19

标签: database database-design versioning

我的原始问题可以找到here,为此我得到了一些很棒的答案,偶像和提示。

作为可行性和性能研究的一部分,我已经开始转换我的模式,以便使用这些想法对我的数据进行版本控制。在这样做的时候,我想出了一些其他的问题。

在我原来的问题中,我的例子很简单,没有真正的关系引用。为了保留我之前问题的例子,我现在将'Name'部分扩展到另一个表。

现在,我的数据变为:

Person
------------------------------------------------
ID                UINT NOT NULL,
NameID            UINT NOT NULL,
DOB               DATE NOT NULL,
Email             VARCHAR(100) NOT NULL

PersonAudit
------------------------------------------------
ID                UINT NOT NULL,
NameID            UINT NOT NULL,
DOB               DATE NOT NULL,
Email             VARCHAR(100) NOT NULL,
UserID            UINT NOT NULL,         -- Who
PersonID          UINT NOT NULL,         -- What
AffectedOn        DATE NOT NULL,         -- When
Comment           VARCHAR(500) NOT NULL  -- Why

Name
------------------------------------------------
ID                UINT NOT NULL,
FirstName         VARCHAR(200) NOT NULL,
LastName          VARCHAR(200) NOT NULL,
NickName          VARCHAR(200) NOT NULL

NameAudit
------------------------------------------------
ID                UINT NOT NULL,
FirstName         VARCHAR(200) NOT NULL,
LastName          VARCHAR(200) NOT NULL,
NickName          VARCHAR(200) NOT NULL,
UserID            UINT NOT NULL,         -- Who
NameID            UINT NOT NULL,         -- What
AffectedOn        DATE NOT NULL,         -- When
Comment           VARCHAR(500) NOT NULL  -- Why

在GUI中,我们可以看到以下形式:

ID            :  89213483
First Name    :  Firsty
Last Name     :  Lasty
Nick Name     :  Nicky
Date of Birth :  January 20th, 2005
Email Address :  my.email@host.com

可以进行更改:

  1. 仅限于'name'部分
  2. 仅限于'人'部分
  3. 同时提供“姓名”和“人物部分”
  4. 如果出现'1',我们将原始记录复制到NameAudit并使用更改更新我们的Name记录。由于人员对名称的引用仍然相同,因此不需要更改Person或PersonAudit。

    如果发生'2',我们将原始记录复制到PersonAudit并使用更改更新Person记录。由于名称部分未更改,因此不需要更改Name或NameAudit。

    如果出现“3”,我们会根据上述两种方法更新数据库。

    如果我们对人员和姓名部分进行100次更改,则稍后尝试显示更改历史记录时会出现一个问题。我的所有更改都显示拥有该姓名的最后一个版本的人。这显然是错的。

    为了解决这个问题,似乎Person中的NameID字段应该引用NameAudit(但仅当Name有更改时)。

    正是这种条件逻辑开始使事情复杂化。

    我很想知道是否有人在使用他们的数据库之前遇到过这种问题并且应用了哪种解决方案?

2 个答案:

答案 0 :(得分:6)

您应该尝试阅读“时间数据库”处理。你可以看到的两本书是Darwen,Date和Lorentzos“Temporal Data and the Relational Model”和(完全不同的极端)“Developing Time-Oriented Database Applications in SQL”,Richard T. Snodgrass,Morgan Kaufmann Publishers,Inc.,San Francisco, 1999年7月,504 + xxiii页,ISBN 1-55860-436-7。已经绝版,但在cs.arizona.edu的网站上以PDF格式提供。您还可以查找间隔“Allen's Relations” - 它们可能对您有所帮助。


我假设数据库中的DATE类型包含时间(因此您可能使用Oracle)。 SQL标准类型可能是TIMESTAMP,具有一些小数位数,用于亚秒级分辨率。如果您的DBMS没有包含DATE的时间,那么您将面临一个难题,即决定如何在一天内处理多项更改。

您需要显示的是,任何一个表中的更改的历史记录,以及在进行更改时生效的另一个表中的相应值。您还需要确定您显示的内容是图像之前还是之后;可能,再次,后图像。这意味着你将有一个'有序'的查询(Snodgrass的术语),其中包含以下列:

Start time        -- When this set of values became valid
End time          -- When this set of values became invalid
PersonID          -- Person.ID (or PersonAudit.ID) for Person data
NameID            -- Name.ID (or NameAudit.ID) for Name data
DOB               -- Date of Birth recorded while data was valid
Email             -- Email address recorded while data was valid
FirstName         -- FirstName recorded while data was valid
LastName          -- LastName recorded while data was valid
NickName          -- NickName recorded while data was valid

我假设一旦建立了Person.ID,它就不会改变;同名为Name.ID.这意味着它们在记录时仍然有效。

其中一个难点是建立正确的“开始时间”和“结束时间”值,因为转换可能发生在任何一个表(或两者)中。我现在还不确定你拥有所需的所有数据。插入新记录时,您不会捕获它变为有效的时间(插入新记录时 XYZAudit 表中没有任何内容,是吗?)。


还有更多可以说的。不过,在进一步讨论之前,我宁愿对目前提出的一些问题有一些反馈。


其他一些可能有帮助的问题:


由于这个答案是第一次写的,所以还发表了另一本关于处理时态数据的另一套称为“断言版本控制”的方法。这本书是Tom Johnston和Randall Weiss的“Managing Time in Relational Databases: How to Design, Update and Query Temporal Data”。您可以在AssertedVersioning.com找到他们的公司。注意:该机制可能存在专利问题。

此外,SQL 2011标准(ISO / IEC 9075:2011,在许多部分中)已经发布。它包括一些时间数据支持。您可以在TemporalData.com找到有关该时间数据和其他与时态数据相关的问题的更多信息,这些信息更像是一般信息网站,而不是具有特定产品的网站。

答案 1 :(得分:0)

使用自动增量ID保留单个更改表,并进行所有更改以引用该表。

始终将原始记录放入审核表。

要构建历史记录,请选择所有更改并显示最接近更改的值。

像这样:

`Change`

1
2
3
4
5
6

`NameAudit`

1 - created as John Smith
5 - changed to James Smith

`PersonAudit`

1 - created as born on `01.01.1980` in `Seattle, WA`
2 - changed DOB to '01.01.1980`
3 - changed DOB to '02.01.1980`
4 - changed DOB to '02.01.1980`
6 - changes POB to `Washington, DC`

然后选择:

SELECT  c.id,
        (
        SELECT   MAX(id)
        FROM     NameAudit na
        WHER     na.id <= c.id
        ) as nameVersion,
        (
        SELECT   MAX(id)
        FROM     PersonAudit pa
        WHER     pa.id <= c.id
        ) as personVersion,
        na.*,
        pa.*
FROM    change c
JOIN    NameAudit na
ON      na.id = nameVersion
JOIN    PersonAudit pa
ON      pa.id = nameVersion
WHERE   change_id BETWEEN 1 AND 6