所以我试图设计一个数据库,允许我将一个产品与多个类别连接起来.这部分我想通了.但我无法解决的问题是持有不同类型的产品细节.
例如,产品可能是一本书(在这种情况下,我需要像isbn,作者等那样引用该书的元数据),或者它可能是商业列表(具有不同的元数据).
我应该怎么解决这个问题?
这个问题与我在其他问题中可以找到的架构有关. 基本上在我的数据库中,我存储用户,位置,传感器等.所有这些都可以由用户在系统中编辑,并且可以删除.
但是 - 当编辑或删除项目时,我需要存储旧数据; 我需要能够在变更之前看到数据是什么.
数据库中还有不可编辑的项目,例如"读数".他们真的更像是一个日志.读数记录在传感器上,因为它是特定传感器的读数.
如果我生成一个读数报告,我需要能够看到读取时位置或传感器的属性.
基本上我应该能够重建任何时间点的数据.
现在,我之前已经完成了这项工作,并通过在每个可编辑表中添加以下列来使其运行良好:
valid_from
valid_to
edited_by
Run Code Online (Sandbox Code Playgroud)
如果valid_to = 9999-12-31 23:59:59则那是当前记录.如果valid_to等于valid_from,则删除记录.
但是,我对我需要用来强制执行外键一致性的触发器感到满意.
我可以通过使用"PostgreSQL"数据库的扩展来避免触发器.这提供了一个名为"period"的列类型,它允许您存储两个日期之间的一段时间,然后允许您执行CHECK约束以防止重叠周期.这可能是一个答案.
我想知道是否有另一种方式.
我见过人们提到使用特殊的历史表,但我真的不喜欢几乎每1个表维护2个表的想法(尽管它仍然可能).
也许我可以砍掉我的初步实施,以不打扰检查不属于"当前"记录的一致性 - 即只懒得去查制约记录中,其中的失效日期9999-12-31 23:59:59.毕竟,使用历史表的人似乎没有对这些表进行约束检查(出于同样的原因,你需要触发器).
有没有人对此有任何想法?
PS - 标题还提到了可审计的数据库.在我之前提到的系统中,总是有edited_by字段.这允许跟踪所有更改,以便我们始终可以看到谁更改了记录.不确定可能会有多大差异.
谢谢.
我需要存储一组实体,其中有几个专用版本.它们具有一些共同属性,但专用属性包含特定于该实体的属性.
数据存储是一个关系型DBMS,这不是讨论:-)具体来说,它是Microsoft SQL Server 2005.
我可以轻松地为公共属性创建一个表,然后为每个专用版本创建一个表.但是,以后可能需要将新实体添加到解决方案中,并且我不希望同时维护对象模型和数据库模式.
另一个想法是创建一个表
reading(<common properties>, extended_properties)
Run Code Online (Sandbox Code Playgroud)
并且该extended_properties
字段是扩展属性的某种序列化.我在想JSON或XML.我很可能会使用ORM框架,但我还没有决定.无论哪种方式,来自的专用实体的对象表示都reading
可以公开{extended_property_name, value}
包含来自该extended_properties
字段的解析的键/值对的字典.
从这个http://msdn.microsoft.com/en-us/library/ms345117(SQL.90).aspx我收集XML字段,结合这些的模式,在DBMS中给出了类型化XML的概念.此外,涉及extended_properties
字段中的XML内容的查询也可以考虑这些.
对我的解决方案建议的反馈,主要是具有reading
扩展属性的表和序列化的建议.
此外,我意识到这是关系DBMS与基于键/值的商店相比的局限性之一.但是,肯定必须有一些建模技术来适应这种情况.
非常感谢任何反馈!
假设我有一张桌子:
CREATE TABLE T
(
TableDTM TIMESTAMP NOT NULL,
Code INT NOT NULL
);
Run Code Online (Sandbox Code Playgroud)
我插入一些行:
INSERT INTO T (TableDTM, Code) VALUES ('2011-01-13 10:00:00', 5);
INSERT INTO T (TableDTM, Code) VALUES ('2011-01-13 10:10:00', 5);
INSERT INTO T (TableDTM, Code) VALUES ('2011-01-13 10:20:00', 5);
INSERT INTO T (TableDTM, Code) VALUES ('2011-01-13 10:30:00', 5);
INSERT INTO T (TableDTM, Code) VALUES ('2011-01-13 10:40:00', 0);
INSERT INTO T (TableDTM, Code) VALUES ('2011-01-13 10:50:00', 1);
INSERT INTO T (TableDTM, Code) VALUES ('2011-01-13 11:00:00', 1);
INSERT INTO …
Run Code Online (Sandbox Code Playgroud) 我在关系数据库中有以下表:
[Sensor]
LocationId [PK / FK -> Location]
SensorNo [PK]
[AnalogSensor]
LocationId [PK/FK -> Sensor]
SensorNo [PK/FK -> Sensor]
UpperLimit
LowerLimit
[SwitchSensor]
LocationId [PK/FK -> Sensor]
SensorNo [PK/FK -> Sensor]
OnTimeLimit
[Reading]
LocationId [PK/FK -> Sensor]
SensorNo [PK/FK -> Sensor]
ReadingDtm [PK]
[ReadingSwitch]
LocationId [PK/FK -> Reading]
SensorNo [PK/FK -> Reading]
ReadingDtm [PK/FK -> Reading]
Switch
[ReadingValue]
LocationId [PK/FK -> Reading]
SensorNo [PK/FK -> Reading]
ReadingDtm [PK/FK -> Reading]
Value
[Alert]
LocationId [PK/FK -> Reading]
SensorNo [PK/FK -> Reading]
ReadingDtm …
Run Code Online (Sandbox Code Playgroud) 我在这个查询的另一个问题的答案中,在PerformanceDBA的声明中提出这个问题:
SELECT ProductId,
Description
FROM Product p,
ProductStatus ps
WHERE p.ProductId = ps.ProductId -- Join
AND StatusCode = 2 -- Request
AND DateTime = ( -- Current Status on the left ...
SELECT MAX(DateTime) -- Current Status row for outer Product
FROM ProductStatus ps_inner
WHERE p.ProductId = ps_inner.ProductId
)
Run Code Online (Sandbox Code Playgroud)
使用ProductStatus表只保存状态随时间变化的有效(开始)日期,将超过此查询:
SELECT ProductId,
Description
FROM Product p,
ProductStatus ps
WHERE p.ProductId = ps.ProductId -- Join
AND StatusCode = 2 -- Request
AND getdate() BETWEEN DateFrom AND Dateto …
Run Code Online (Sandbox Code Playgroud)