如何在基于SQL的数据库中正确建模数据,这些数据库具有一些共同的列,但也具有唯一的列?

时间:2010-04-02 19:37:15

标签: sql mysql database database-design data-modeling

例如,假设我有一个User模型。用户有登录,密码,电子邮件地址,头像等等。但是有两种类型的用户将使用这个网站,比如父母和企业。我需要为父母存储一些不同的信息(例如孩子的姓名,家庭伴侣,工资等),而不是商业(例如行业,员工人数等),但也有一些是相同的,比如登录和密码。

如何在基于SQL的数据库中正确构建它?谢谢!

- UPDATE -

在挖掘了一点之后,我认为多态关联可能实际上更有意义。但是我对他们了解不多,我有什么理由不想使用它们,或者说STI更好?它们似乎完全相同,只是父母或企业特有的字段存储在单独的表中,我认为这是我想要的。不是吗?

5 个答案:

答案 0 :(得分:3)

在这种情况下,我发现以下是最佳方法:

  • 创建一个表来保存两种类型的用户;此表将为两种类型的用户共享的每个属性提供一列;
  • 为每种类型创建一个辅助表,每个类型中的外键指向Users表;这些表只有每种类型的额外属性,加上用户的外键;

通过这种方式,您可以避免在数据库中出现数据稀缺问题,并且扩展表中只有那么多的记录存在该类型的用户。如果您正在使用代码生成工具,则可以为每个扩展表生成一个用户作为其父属性的扩展表,允许您访问所有字段。您可能还希望为users表本身生成,因为当您处理所有用户时,无论其类型如何。

我希望这是有道理的,而且它会有所帮助。

干杯!

答案 1 :(得分:1)

通常,您将拥有一个Users表,其中包含父母和企业共有的所有字段以及名为UserID的唯一ID。然后在Parents表中,您将拥有UserID(链接回Users表)和父项独有的字段。同样,您将拥有一个具有UserID字段的Businesses表以及对于企业而言唯一的字段。这是您设置normalized数据库的方法。 Parent和Businesses表中的UserID字段将是一个返回Users表的引用(外键)。

答案 2 :(得分:1)

在面向对象的环境中,这将通过继承进行建模。有几种方法可以将继承映射到数据库表。最简单的是Single Table Inheritance。如果你有一个面向对象的环境消耗数据库,这值得研究。

更新:STI与其他替代方案

如果不同的字段数量很少,我会选择STI,因为这很容易实现,并且不需要额外的连接。另外两个主要的替代方案是

  • 每班表
  • 每个混凝土类别的表格

每班表

如果类型之间有很多不同的字段,那么它是首选的。缺点是几乎所有查询都需要在基类表和一个或多个子类表之间进行连接操作。

每个混凝土类的表

为了解决每个表的连接问题,每个混凝土类的表是另一种方法。但是,它要求属于抽象基类的公共字段存在于多个表中。这违反了DRY原则,并要求联合查询从几个具体类型中获取公共属性。

答案 3 :(得分:1)

在数据库中建模关系会增加很多复杂性。例如,辅助表(也称为1:1关系)在每个查询中需要join

select u.name, p.DomesticPartner
from users u
join users_partners p on p.userId = u.id

动态列(1:多个名称对值)为您查询的每个列添加一个join

select n.value as Name, p.value as DomesticPartner
from users u
join users_columns n on n.name = 'Name' and n.userid = u.id
join users_columns p on p.name = 'DomesticPartner' and p.userid = u.id

你必须权衡这种复杂性与关系提供的附加价值。

对于我自己来说,作为一个经验法则,我避免使用数据库关系,除非有令人信服的理由。示例令人信服的原因:

  • 在开发时不知道列名称
  • 行大小将超过数据库允许的最大值
  • 关系本身模拟信息(例如客户和订单)

在您的情况下,我只是将所有列添加到用户表中。您可以使用check约束来强制使用未使用的列:

CHECK (UserType = 'Parent' OR DomesticPartner IS NULL)

答案 4 :(得分:0)

看一下类似问题的this question/answer,它描述了超类型/子类型关系。