与不同数据类型的多对多关系

时间:2016-09-22 08:14:22

标签: sql sql-server database-design many-to-many entity-attribute-value

我们的应用程序已经过定制,可以处理许多不同类型的客户,某些设置仅适用于少数或一个客户。而不是不断地将可空列添加到customers表, 我决定添加一个[设置]表,以允许每个设置为一行。

[dbo].[Settings]
    [SettingID] [int] 
    [SettingCode] [nchar](4)
    [SettingDescription] [nvarchar](255) 

然后通过多对多表

将其链接到[Customers]表
[dbo].[Customer_Settings]
    [Customer_SettingsID] [int]
    [CustomerID] [int] 
    [SettingID] [int] 

我的问题是如何处理这些设置中的许多设置需要[Customer_Settings]表上的其他数据类型。

例如,我们可以将一个设置设置为需要时间数据类型的“最新交付时间”,或者另一个设置为“需要一个int的分钟到期”。

我能想到的两种方法是将可为空的列添加到[Customer_Settings]表中,如:

[dbo].[Customer_Settings]
    [Customer_SettingsID] [int]
    [CustomerID] [int] 
    [SettingID] [int] 
    [ValueTime] [time] NULL
    [ValueInt] [int] NULL
    ...

这看起来很糟糕。

我能想到的另一种方法是将子表添加到[Customer_Settings]表中,如:

[dbo].[Customer_Settings_Int]
    [Customer_Settings_Int_ID] [int]
    [Customer_SettingsID] [int]
    [Value] [int]

这似乎是规范化的,但也很麻烦。如果其中一个显然更好或者有其他选择,请告诉我。谢谢!

2 个答案:

答案 0 :(得分:0)

您选择的解决方案称为Entity-Attribute-Value (EAV.)最常见的方法是将所有值存储为字符串。有些人添加了一个包含正则表达式或类似表达式的验证器列,该列由客户端或更新值的t-sql函数验证。

使用可以为空的列要清晰得多。

答案 1 :(得分:0)

看起来您可能能够将多组属性收集到逻辑分组中,而不是单例属性列表。你提示"交付的东西"和"到期的东西"这可能是两个这样的分组。在查找表中创建这些分组的列表,如下所示:

ID  Name         Description
 D  Deliverable  Something that is delivered
 E  Expirable    Something that expires

然后为客户和分组创建一种交集表(具有分组类型)

create table CustGrouping(
    CustID   int not null references Customer( ID ),
    GroupID  int auto_generated,
    GroupType char( 1 ) not null references Groupings( ID ), -- the table above
    constraint PK_CustGrouping primary key( CustID, GroupID ),
    constraint UQ_Group_Type unique( GroupID, GroupType )
);

PK会防止意外地将客户与同一个分组多次配对。当GroupID本身是唯一的时,为什么要在(GroupID,GroupType)上创建唯一约束?所以它可以作为外键的参考点。

每个分组都需要一个单独的表格。这只是一个:

create table Deliverables(
  ID    int  not null primary key,
  TypeID char( 1 ) not null check( TypeID = 'D' ),
  DeliveryDate date not null,
  ..., -- all other fields that are associated with deliverables
  constraint FK_Deliverables_CustGrouping foreign key( ID, TypeID )
    references CustGrouping( GroupID, GroupType )
);

检查约束显示了如何只将可交付数据写入该表。

以下是操作顺序:

  1. 为客户生成可交付成果时,请使用客户ID和分组指定符(' D')插入到CustGrouping。这将生成此交付项的ID。
  2. 使用生成的ID,将可交付物数据插入Deliverables表。
  3. 其他分组也采用相同的操作。分组ID确保该组的FK只能引用正确类型的分组。它还可以让您知道哪个表包含数据,并且这些数据对于每种分组都可以完全不同。它的可扩展性是,为了添加新类型的分组,将定义插入到Groupings表中,创建一个表来包含所需长度和格式的数据,并从那里开始。

    我还建议创建视图以显示每种分组的客户数据。例如,视图CustomerDeliverables显示带有可交付物的客户数据。因此,当应用程序的一部分只使用可交付成果时,它不需要知道如何将其存储在数据库中的细节。视图上的触发器可以轻松创建,删除和操作分组数据。