T.J*_*der 5 sql t-sql database-design
我需要存储与"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)
)
Run Code Online (Sandbox Code Playgroud)
很简单,汽车进去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)
)
Run Code Online (Sandbox Code Playgroud)
所以每辆车都有一排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)
)
Run Code Online (Sandbox Code Playgroud)
所以每辆车都有一排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)
)
Run Code Online (Sandbox Code Playgroud)
所以Car数据会将Style分配给Detail01,Color to Detail02和EngineSize Detail03; 对于Boats,我们将Displacement Detail01和PortOfOrigin放入Detail02.同样,对于最终用户定义的模式,可能存在这样的地方,但我猜这可以控制数据库结构时不是一个好的答案.
小智 6
这取决于.
方法1最适用于大多数类型通用的大多数属性的情况.
方法2最适用于大多数类型的公共属性很少的情况.
方法3基本上是方法1,使用实体 - 属性 - 值方法来处理特定于类型的属性.这种方法最适用于大多数类型对大多数类型都是通用的情况,并且很难预测需要哪些附加属性 - 在需要用户创建的字段的情况下这种情况很常见.
方法4在任何情况下都不是一个好主意 - 它将语义内容从元数据层移除到代码层,同时保留方法1的不灵活性.
还有另一种可能的方法 - 纯实体 - 属性 - 值方法(基本上是方法3和4的混合).由于在RDBMS上实现时产生的复杂性和不良性能,这通常被视为反模式.但是,在某些情况下,这是唯一可能的方法 - 主要是在事先不知道实体关系的情况下.