项目和专用项目:具有重复列,主表和详细信息表的多个表,或......?

时间:2012-03-06 13:12:11

标签: sql tsql database-design

我需要存储与“items”相关的数据,其中将存在各种不同的项类型,所有项都具有公共属性,然后每种类型都有自己的附加属性。我希望这是一个共同的要求;什么是最佳实践解决方案?我们正在使用SQL Server。

让我们使用一个简单的例子:

车辆

  • 价格
  • 模型
  • 所有者

(在我们的实际数据中,将有10-15个常用列。)

汽车是车辆加号:

  • 风格(轿车,运动等)
  • 颜色
  • EngineSize

是车辆加号:

  • 位移
  • PortOfOrigin

...等。对于几种类型的东西。在我们的实际数据中,每种专用类型通常会添加2-5列;将有5种类型开始。我们将随着时间的推移添加类型,但总共可能只增加3或4个(如果是这样)。添加类型需要开发,因此它不像最终用户可以添加的“标签”。我们假设添加类型将需要更改数据库和客户端层,也可能需要更改中间层。那完全没问题。

我们会对所有项目(车辆,在上面的示例中)进行大量查询;我们很少担心特定物品类型(汽车,船)的细节。

我看到了存储这些数据的四种方法:

  1. 包含重复列的汽车,小船等的单独表格。
  2. 包含Vehicle数据的一个表格,其他Car数据的表格以及其他Boat数据的表格。
  3. 一个项目表,一个单独的项目属性表,每个附加属性有一行。例如,细节的软模式。
  4. 一个只包含非DB代码的通用列表。
  5. 看着每个人:

    1. 包含重复列的汽车,小船等的单独表格。例如,粗略地说:

      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列)。

    2. 一个包含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表格对车辆进行报告。在检索特定CarBoat的详细信息时,我们会使用联接。

    3. 一个项目表,一个单独的项目属性表,每个附加属性有一行。例如,细节的软模式。例如,粗略地说:

      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表进行。报告细节开始变得混乱快速。软模式有它们的位置,主要是围绕用户定义的数据,但我认为这不是一个好的选择。

    4. 一个包含通用列的表仅由非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放在一起。同样,对于最终用户定义的模式,可能会有这样的地方,但我猜这可以控制数据库结构,这不是一个好的答案。

1 个答案:

答案 0 :(得分:6)

取决于。

方法1最适用于大多数类型都具有大多数属性的情况。

方法2最适用于大多数类型中很少有属性的情况。

方法3基本上是方法1,使用实体 - 属性 - 值方法来处理特定于类型的属性。这种方法最适用于大多数类型的大多数属性都很常见的情况,并且很难预测需要哪些附加属性 - 在需要用户创建的字段的情况下这种情况很常见。

方法4在任何情况下都不是一个好主意 - 它将语义内容从元数据层移除到代码层,同时保留方法1的不灵活性。

还有另一种可能的方法 - 纯Entity-Attribute-Value方法(基本上是方法3和方法4的混合)。由于在RDBMS上实现时产生的复杂性和不良性能,这通常被视为反模式。但是,在某些情况下,这是唯一可能的方法 - 主要是在事先不知道实体关系的情况下。