我需要存储与“items”相关的数据,其中将存在各种不同的项类型,所有项都具有公共属性,然后每种类型都有自己的附加属性。我希望这是一个共同的要求;什么是最佳实践解决方案?我们正在使用SQL Server。
让我们使用一个简单的例子:
车辆有
(在我们的实际数据中,将有10-15个常用列。)
汽车是车辆加号:
船是车辆加号:
...等。对于几种类型的东西。在我们的实际数据中,每种专用类型通常会添加2-5列;将有5种类型开始。我们将随着时间的推移添加类型,但总共可能只增加3或4个(如果是这样)。添加类型需要开发,因此它不像最终用户可以添加的“标签”。我们假设添加类型将需要更改数据库和客户端层,也可能需要更改中间层。那完全没问题。
我们会对所有项目(车辆,在上面的示例中)进行大量查询;我们很少担心特定物品类型(汽车,船)的细节。
我看到了存储这些数据的四种方法:
Vehicle
数据的一个表格,其他Car
数据的表格以及其他Boat
数据的表格。看着每个人:
包含重复列的汽车,小船等的单独表格。例如,粗略地说:
CREATE TABLE [Cars] (
[Id] IDENTITY PRIMARY KEY,
[Price] DECIMAL (19, 4),
[Make] NVARCHAR(200),
[Model] NVARCHAR(200),
[Owner] INT,
[Id] INT PRIMARY KEY,
[Style] NVARCHAR(200),
[Color] NVARCHAR(200),
[EngineSize] DECIMAL(19, 2)
)
CREATE TABLE [Boats] (
[Id] IDENTITY PRIMARY KEY,
[Price] DECIMAL (19, 4),
[Make] NVARCHAR(200),
[Model] NVARCHAR(200),
[Owner] INT,
[Id] INT PRIMARY KEY,
[Displacement] DECIMAL(19, 4),
[PortOfOrigin] NVARCHAR(200)
)
很简单,汽车进入Cars
,而船只进入Boats
。如果我们添加更多车型,我们会添加一个表格。如果我们添加另一个公共列,我们必须返回并将其添加到所有车辆表中。一般情况下,针对车辆的报告可以针对所有表格的联合视图进行(注意Id
列)。
一个包含Vehicle
数据的表,一个用于附加Car
数据的表,以及一个用于附加Boat
数据的表。例如,粗略地说:
CREATE TABLE [Vehicles] (
[Id] IDENTITY PRIMARY KEY,
[Price] DECIMAL (19, 4),
[Make] NVARCHAR(200),
[Model] NVARCHAR(200),
[Owner] INT,
[Type] INT -- A type ID, e.g. "Car" vs. "Boat"
)
CREATE TABLE [Cars] (
[Id] INT PRIMARY KEY,
[Style] NVARCHAR(200),
[Color] NVARCHAR(200),
[EngineSize] DECIMAL(19, 2)
)
CREATE TABLE [Boats] (
[Id] INT PRIMARY KEY,
[Displacement] DECIMAL(19, 4),
[PortOfOrigin] NVARCHAR(200)
)
所以每辆车在Vehicles
中都有一行,在Cars
中有一行。每艘船在Vehicles
中都有一行,Boats
中有一行。如果我们添加更多车型,我们会添加一个表格。通常可以仅针对Vehicle
表格对车辆进行报告。在检索特定Car
或Boat
的详细信息时,我们会使用联接。
一个项目表,一个单独的项目属性表,每个附加属性有一行。例如,细节的软模式。例如,粗略地说:
CREATE TABLE [Vehicles] (
[Id] IDENTITY PRIMARY KEY,
[Price] DECIMAL (19, 4),
[Make] NVARCHAR(200),
[Model] NVARCHAR(200),
[Owner] INT,
[Type] INT
)
CREATE TABLE [VehicleDetails] (
[VehicleId] INT,
[Name] NVARCHAR(200),
[Value] NVARCHAR(MAX)
)
因此,每辆车在Vehicles
中获得一行,在VehicleDetails
中获得三行(“Style”,“Color”和“EngineSize”各一行)。报告主要针对Vehicle
表进行。报告细节开始变得混乱快速。软模式有它们的位置,主要是围绕用户定义的数据,但我认为这不是一个好的选择。
一个包含通用列的表仅由非DB代码表示:
CREATE TABLE [Vehicles] (
[Id] IDENTITY PRIMARY KEY,
[Price] DECIMAL (19, 4),
[Make] NVARCHAR(200),
[Model] NVARCHAR(200),
[Owner] INT,
[Type] INT,
[Detail01] NVARCHAR(MAX),
[Detail02] NVARCHAR(MAX),
[Detail03] NVARCHAR(MAX),
[Detail04] NVARCHAR(MAX),
[Detail05] NVARCHAR(MAX),
[Detail06] NVARCHAR(MAX),
[Detail07] NVARCHAR(MAX),
[Detail08] NVARCHAR(MAX),
[Detail09] NVARCHAR(MAX),
[Detail10] NVARCHAR(MAX)
)
因此,Car数据会将Style指定为Detail01
,Color指定为Detail02
,EngineSize指定为Detail03
;对于Boats,我们将Detail01
中的Displacement和Detail02
中的PortOfOrigin放在一起。同样,对于最终用户定义的模式,可能会有这样的地方,但我猜这可以控制数据库结构,这不是一个好的答案。
答案 0 :(得分:6)
取决于。
方法1最适用于大多数类型都具有大多数属性的情况。
方法2最适用于大多数类型中很少有属性的情况。
方法3基本上是方法1,使用实体 - 属性 - 值方法来处理特定于类型的属性。这种方法最适用于大多数类型的大多数属性都很常见的情况,并且很难预测需要哪些附加属性 - 在需要用户创建的字段的情况下这种情况很常见。
方法4在任何情况下都不是一个好主意 - 它将语义内容从元数据层移除到代码层,同时保留方法1的不灵活性。
还有另一种可能的方法 - 纯Entity-Attribute-Value方法(基本上是方法3和方法4的混合)。由于在RDBMS上实现时产生的复杂性和不良性能,这通常被视为反模式。但是,在某些情况下,这是唯一可能的方法 - 主要是在事先不知道实体关系的情况下。