【发布时间】:2012-03-23 23:19:42
【问题描述】:
我需要存储与“项目”相关的数据,其中会有各种不同的项目类型,所有项目类型都有共同的属性,然后每种类型都有自己的附加属性。我希望这是一个常见的要求;什么是最佳实践解决方案?我们正在使用 SQL Server。
让我们用一个虚构的例子:
车辆有
- 价格
- 制作
- 型号
- 所有者
(在我们的真实数据中,会有10-15个常见的列。)
汽车是车辆加号:
- 风格(轿车、运动等)
- 颜色
- 引擎尺寸
船是车辆加号:
- 位移
- PortOfOrigin
...等等。对于几种类型的东西。在我们的真实数据中,每个特殊类型通常会添加 2-5 列;将有 5 种类型开始。随着时间的推移,我们将添加类型,但总共可能只有 3 或 4 个(如果有的话)。添加类型需要开发,因此它不像最终用户可以随意添加的“标签”。我们假设添加类型将需要更改数据库和客户端层,可能还需要更改中间层。完全没问题。
我们将对所有项目(车辆,在上面的示例中)进行大量查询;我们很少担心特定项目类型(汽车、船)的细节。
我看到了四种存储这些数据的方法:
- 用于 Cars、Boats 等的单独表格,具有重复的列。
- 一个包含
Vehicle数据的表,一个包含附加Car数据的表,以及一个包含附加Boat数据的表。 - 一个项目表,一个单独的项目属性表,每个附加属性一行。例如,详细信息的软架构。
- 具有通用列的表仅由非数据库代码赋予含义。
查看每个:
-
用于 Cars、Boats 等的单独表格,具有重复的列。例如,大致:
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中获得三排(“样式”、“颜色”和“引擎尺寸”各有一个)。报告主要针对Vehicle表进行。详细报告开始变得非常混乱。软模式有它们的位置,主要是围绕用户定义的数据,但我认为这不是一个好的选择。 -
一个具有通用列的表,仅由非数据库代码赋予含义:
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,我们将 Displacement 放入Detail01,将 PortOfOrigin 放入Detail02。同样,最终用户定义的模式可能有一个地方,但我猜当你可以控制数据库结构时,这不是一个好的答案。
【问题讨论】:
-
关系型数据库有严格要求吗?看起来对这个模型使用文档数据库会更合适。
-
@Oded:好问题。在这种情况下,是的,它必须存储在 RDBMS 中,至少现在是这样。如果我们得到足够多的这类需求,也许我们会用文档数据库来扩充 RDBMS。
-
“随着时间的推移,我们将添加更多类型” - 向我表示选项 2。与通用列一样,软模式(EAV 模型)不是首发。
-
@Oded:是的,我走上了软模式的道路,然后说“那不会很好”。 :-) 为了完整性,主要包括 3 和 4。
标签: sql tsql database-design