这个问题与我的其他问题之一中可以找到的模式有关 这里。 基本上,在我的数据库中,我存储用户,位置,传感器等。所有这些内容都是用户在系统中可编辑的,并且可以删除。

但是 - 当项目被编辑或删除时,我需要存储旧数据;我需要能够在更改之前查看数据是什么。

数据库中也有不可编辑的项目,例如“读取”。它们实际上更像是日志。读数是针对传感器记录的,因为它是特定传感器的读数。

如果我生成读数报告,我需要能够查看位置或传感器的属性 在阅读时.

基本上,我应该能够在任何时间点重建数据。

现在,我以前做过此操作,并通过将以下列添加到每个可编辑表中,使其运行良好:

valid_from
valid_to
edited_by

如果有效_TO = 9999-12-31 23:59:59,那就是当前记录。如果有效_TO等于有效_from,则将删除记录。

但是,我从来没有对我需要使用的触发器来实施外国密钥一致性。

我可以通过使用“ PostgreSQL”数据库的扩展名来避免触发器。这提供了称为“周期”的列类型,该列类型使您可以在两个日期之间存储一段时间,然后允许您检查约束以防止重叠的时间。这可能是一个答案。

我想知道是否有另一种方法。

我已经看到人们提到使用特殊的历史表,但是我真的不喜欢将2张桌子维护几乎每张1张桌子维护(尽管仍然可能是可能的)。

也许我可以减少我的初始实现,以免检查不是“当前”的记录的一致性 - 即仅费心检查有效_TO为9999-12-31 23:59:59的记录的约束。毕竟,使用历史表的人似乎对这些表没有约束检查(出于相同的原因,您需要触发器)。

有人对此有任何想法吗?

PS-标题还提到可审核数据库。在我提到的上一个系统中,总有edited_by字段。这允许跟踪所有更改,因此我们总是可以看到谁更改了记录。不确定会产生多少差异。

谢谢。

有帮助吗?

解决方案

修订了01年1月11日

好的,所以我坐着的位置存在差距(提供完全可审计的数据库;您的特定要求)和您所在的位置:根据您的问题和评论。我们可能会在评论中解决这些问题。这是一个开始的位置。

  • 为了提供此要求,根本不需要:触发器;大量重复;破碎的完整性;等等

  • 这也不是经典的时间要求,所以不 需要 对于“时期”功能,但是您 能够.

  • 有效From 有效TO是一个归一化错误:有效TO是容易得出的数据;在下一行的有效范围内,在任何行中有效均重复;您有一个更新异常(当您在一行中更新一个列时,还必须在下一行中更新另一列);您必须为“当前”使用虚拟值。

    • 所有不必要的,仅使用有效,然后保持数据库清洁和纯5NF。

    • 警告是,如果PostgreSQL无法在不落入堆(Ala Oracle)的情况下执行子征服,则可以通过kep有效。

所有这些内容都是用户在系统中可编辑的,并且可以删除。

好吧,不。这是一个持有重要信息的数据库;有了参考完整性,而不是刮擦板,因此用户不能仅仅走到它上并“删除”某些东西。它将与维护历史数据(在阅读中;警报; ACK; Action;下载)的相同用户要求相矛盾。

  • 不允许级联删除。这些功能是非数据库,MS访问类型的复选框。对于真实的数据库,RI约束阻止父母与孩子被删除。

  • 主键不能(不应)更改。例如。用户身份;位置; NetworkSlaveCode永远不会更改;记住,他们被仔细考虑 身份标识. 。 PK的一个特征是它们是稳定的。

  • 您可以添加新用户;你可以更改 当前的 用户名;但是您无法删除具有下载,确认和操作的用户。

基本上,如果可以编辑,则必须是历史性的(因此不包括读数和警报)。

也排除:下载;致谢;动作。

和参考表:感觉类型; AlertType; ActionType。

还有新的历史表:它们已插入,但无法更新或删除。

我在IsobSelete标志中发现的问题是..说,如果您更改位置,传感器外键现在将指向obselete记录,这意味着您必须复制每个传感器记录。随着Hierachy的变化,此问题呈指数级别。

  • 好,所以现在您了解 LocationId (fk)在 Sensor 不会改变;没有大量重复等等?首先,没有问题(在那本愚蠢的书中!)在第二位会呈指数级数。

  • IsObsolete 不足以满足您的要求。 (请参阅下面)

  • UpdatedDtm 在任何真实的行(Reading, ,等)标识父(fk至 Sensor)历史行(它 AuditedDtm)当时有效。

  • 完全的关系能力;声明性的改进完整性,等等。

  • 维护强大标识符的IDEF1X,关系概念...只有一个当前的父行(例如位置)

  • 历史上的行是当前行的图像,在更改之前,在说明 AuditedDtm. 。当前行显示了一个最后一个更新的DTM,当该行更改时,当前行(非历史)显示。

  • AuditedDtm 显示整个系列 UpdatedDtms 对于任何给定的钥匙;因此,我将其用来“分区”时间含义。

所需的只是每个可更改表的历史表。我为四个识别表提供了Hiastory表:位置;传感器; NetworkSlave;和用户。

请阅读此信息以理解 会计意义上的审计.

数据模型

链接到 具有历史的传感器数据模型 (第2页包含历史表和上下文)。

不熟悉关系建模标准的读者可能会发现 IDEF1X表示法 有用。

对评论的回应

(1) 我的第一个问题是具有历史数据的参考完整性,因为我不确定是否存在,如果有我不确定它是如何工作的。例如,在SensoryHistory中,可以添加一个记录,该记录具有更新的DTM,该记录表示位置本身存在之前的日期时间,如果您明白了我的意思。我不确定这实际上是一个问题 - 强制执行可能是顶部的问题。

(您在另一个问题中提出了类似的问题。)可能是您所经历的DBS实际上没有具有参考完整性;关系线只是为了文档; RI是“在App Code中实现的”(这意味着没有RI)。

这是ISO/IEC/ANSI标准SQL数据库。这允许声明的参考完整性。每个关系行被用作PK :: FK参考,这是声明的实际约束。例如:

CREATE TABLE Location
    ...
    CONSTRAINT UC_PK
        PRIMARY KEY (LocationId)
    ...
CREATE TABLE Sensor
    ...
    CONSTRAINT UC_PK
        PRIMARY KEY (LocationId, SensorNo)
    CONSTRAINT Location_Sensor_fk
        FOREIGN KEY (LocationId)
        REEFERENCES Location(LocationId)
    ...
CREATE TABLE SensorHistory
    ...
    CONSTRAINT UC_PK
        PRIMARY KEY (LocationId, SensorNo, UpdatedDtm))
    CONSTRAINT Sensor_SensorHistory_fk
        FOREIGN KEY (LocationId, SensorNo)
        REEFERENCES Sensor (LocationId, SensorNo)
    ...
这些声明的约束是由服务器执行的;不是通过触发器;不在应用代码中。这意味着:

  • 一个 SensorLocationId 那不存在 Location 无法插入
  • 一个 LocationIdLocation 有行 Sensor 无法删除
  • 一个 SensorHistoryLocationId+SensorNo 那不存在 Sensor 无法插入
  • 一个 LocationId+SensorNoSensor 有行 SensorHistory 无法删除。

(1.1) 全部 列应具有规则并检查约束以限制其值范围。除了所有插入/更新/删除的事实外,在存储的Procs中都是编程的,因此不会发生事故,并且人们不会走到数据库并对其进行运行命令(选择除外)。

通常,我远离触发器。如果您使用的是存储的Procs和正常的权限,则可以:

在SensoryHistory中,可以添加具有更新的记录,该记录指示位置本身存在之前的日期时间,如果您明白了我的意思

被阻止。因此,比传感器本身更早地插入具有更新DTM的传感史。但是Procs不是声明性的规则。但是,如果您想双重确定(我的意思是双重,因为这些插入都是通过Proc,用户直接命令的),那么,您必须使用触发器。对我来说,那是顶部。

(2) 我如何表示删除?我可以在表格的非历史版本中添加一个标志。

还不确定。例如。你接受吗 Sensor 已删除,这是最终...(是的,历史记录)...然后是新的 Sensor 被添加到 Location, ,它将有一个新的 SensorNo ...没有 Sensor 在逻辑上替换为新的,有或没有时间差距吗?

从最终用户的角度来看,通过软件,他们应该能够随意添加,编辑和删除传感器,而无需限制。但是,是的,一旦被删除,它就会被删除,无法被删除。尽管有完全相同的参数,但没有什么可以阻止他们重新添加传感器。

和“删除” Locations, NetworkSlaves, , 和 Users 也是。

好的。然后是新的 Sensor 使用相同的参数,确实是新的,它有一个新的 SensorNo, ,并且独立于任何以前的逻辑 Sensor. 。我们可以添加一个 IsObsolete 布尔值四个识别表;现在被认为是足够的。删除现在是软删除。

(2.1) NetworkSensorLoggerSensor, ,实际上取决于两个父母:如果他们的任何一个父母都过时,他们就过时了。因此,没有意义 IsObsolete 列,具有双重含义,可以从适用的父派得出。

(2.2)要明确,用户无法从任何交易和历史表中删除任何行,对吗?

(3) 更新表时,哪种方法最好将新行插入历史表并更新主表?只是在交易中的正常SQL语句吗?

是的。这是交易的经典用途,根据酸性特性,它是原子。它要么成功地取得成功,要么失败了(在解决问题时将在以后重试)。

(4)引用书籍

确定和开创性的文字是 时间数据和关系模型 CJ Date,H Darwen,Na Lorentzos。就像在我们那些拥抱RM的人一样,对RM的继任者需要什么;而不是其他方法。

引用的书是可怕的,而且是免费的。 PDF不是PDF(无搜索;无索引)。打开我的MS和Oracle在说明;一些好碎片在很多绒毛上couch。许多虚假陈述。不值得详细回应(如果您想进行适当的审查,请打开一个新问题)。

(4.1) ValidTo 此外 ValidFrom. 。这本书犯的严重错误(如我的回答的顶部所确定的);然后费力地解决。首先不要犯错误,您没有什么可解决的。据我了解,这将消除您的触发因素。

(4.2)简单的规则,同时考虑到归一化和时间要求。首先,您需要深入了解(a)时间要求和(b)数据类型,正确的用法和限制。总是存储:

  • 即时作为日期时间,例如。更新DTM

  • 间隔为整数,清楚地识别列名中的单元,例如。 Intervalsec

  • 时期。取决于连词或分离。

    • 对于连接,此要求是(4.1)适用:使用一个日期时间;该期间的结束可以从下一行的开始的开始。
    • 对于分离的期限,是的,您需要2个X数据,例如 RentedFromRentedTo 介于两者之间。

(4.3)他们弄乱了“时间主键”,这使代码复杂化(除了要求触发器控制更新异常外)。我已经交付了一个干净(经过测试和测试)的时间主键。

(4.4)他们与“现在”的虚拟值,非现实值和nulls混乱。我不允许在数据库中这样的事情。由于我没有存储重复的 ValidTo, ,我没有问题,没有什么可解决的。

(4.5)必须怀疑为什么PDF表格差的528页“教科书”在网络上免费提供。

(5) 我[用户]可以愉快地安静地删除所有位置历史行(仅在位置表中保留当前版本) - 即使可能存在一个概念上“属于”位置的先前版本的传感史行,如果那讲得通。

这对我没有意义,我们必须关闭的沟通差距仍然存在差距。请继续互动,直到关闭。

  • 在真实的(标准ISO/IEC/ANSI SQL)数据库中,我们会这样做 不是 授予用户授予插入/更新/删除权限。我们授予选择和参考 只要 (对选择的用户)所有插入/更新/删除均在交易中编码,这意味着存储的Procs。然后,我们将每个存储的POC上的Exec授予选定的用户(使用角色来减少管理)。

    • 因此,没有人可以在没有执行proc的情况下从任何表中删除。

    • 请勿编写proc从任何历史记录表中删除。这些行不应删除。在这种情况下,代码的无权和不存在 约束。

    • 从技术上讲,所有历史行都是有效的,没有任何时期可以关注自己。最古老的位置历史行包含原始位置行更改之前的前图。最年轻的位置历史行是当前位置行的前图。因此,之间的每个位置历史行都是有效的,并适用于之间的周期。

    • 无需“修剪”或寻找可以根据不使用的时期删除的几个位置历史行: 他们都被用. 。 (确切地说,无需检查任何位置的映射儿童到任何位置历史行的映射,以证明它。)

    • 底线:用户无法从任何历史记录(或事务)表中删除。

    • 还是您的意思再次有所不同?

    • 请注意,我上面添加了(1.1)。

(6)纠正了DM中的一个错误。一个 AlertReading, , 不是 Sensor.

(7)在另一个问题/答案中纠正了业务规则,以反映这一点;并在这个问题中暴露了新规则。

(8)您理解/欣赏吗? 身份标识:

  • 标识符通过整个数据库携带,并保留其功率。例如。列表时 Acknowledgements, ,它们可以直接与 LocationSensor;之间的表格不必读(必须是 Id 使用键)。这就是为什么在关系数据库中所需的实际上所需的加入的原因(并且在一个未正常的数据库中需要更多的加入)。

  • 需要导航子类型等 只要 当这种特定上下文是相关的时。

其他提示

我以前也遇到过这种情况。根据您试图跟踪的数据量,这可能令人生畏。历史表有时可以易于使用,因为您可以在“历史表”表中拍摄记录的“快照”,然后根据需要在生产表中进行更改。实施非常直接,但是取决于您拥有的数据和变化的频率,您最终可以得到很大的历史表。

另一个选择是记录所有更改,使某人可以“重播”发生的事情并跟踪它。每次更改都登录到表或字段(取决于您的需求),以跟踪2010年12月31日在2010年12月31日更改为IE的谁,何时以及更改的状态从“开放”更改为“封闭”。

您要使用的系统通常取决于您需要如何保留/查看/以后使用数据。自动报告,一个人审查,两者的某种组合等等。

根据您的预算和/或环境,您可能需要考虑使用Oracle的闪回存档功能。

您可以打开表中的行自动“归档”,然后使用类似的内容在地下室上运行语句

SELECT *
FROM important_data
AS OF TIMESTAMP (SYSTIMESTAMP - INTERVAL '5' DAY)

Oracle照顾在单独的(阴影)表中维护历史记录。您可以为任何桌子执行此操作,以便您也可以使用JOIN进行查询。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top