设计此特定数据库/ SQL问题的最佳方法是什么?

时间:2010-10-20 21:02:51

标签: sql database-design normalization

这是一个令我们困惑的棘手的规范化/ SQL /数据库设计问题。我希望我能正确说明。

您有一系列活动。他们是需要做的事情 - 一个荣耀的TODO清单。任何给定的活动都可以分配给员工。

每项活动也都有活动进行的活动。这些活动是联系人(个人)或客户(业务)。然后,每个活动都将有一个联系人或一个将为其开展活动的客户。例如,活动可能是“向Spacely Sprockets(客户)发送感谢卡”或“向Tony Almeida发送营销资料(联系人)”。

从那个结构中,我们需要能够查询以查找给定员工必须完成的所有活动,将它们列在一个最简单形式的单一关系中:

-----------------------------------------------------
| Activity | Description    | Recipient of Activity |
-----------------------------------------------------

这里的想法是避免为Contact和Customer提供两列null,其中一列为null。

我希望我已经正确地描述了这一点,因为这并不像乍看之下那么明显。

所以问题是:数据库的“正确”设计是什么?如何查询它以获取所要求的信息?

11 个答案:

答案 0 :(得分:9)

这听起来像是一个基本的多对多关系,我会这样建模。

alt text

答案 1 :(得分:4)

这个数据库的“正确”设计是每个都有一列,你说你试图避免。这允许在这两列及其各自的表之间定义适当的外键关系。对引用两个不同表的键使用相同的列将使查询变得丑陋,并且您无法强制执行引用完整性。

活动表应具有外键ContactID,CustomerID

显示员工的活动:

SELECT ActivityName, ActivityDescription, CASE WHEN a.ContactID IS NOT NULL THEN cn.ContactName ELSE cu.CustomerName END AS Recipient
FROM activity a
LEFT JOIN contacts cn ON a.ContactID=cn.ContactID
LEFT JOIN customers cu ON a.CustomerID=cu.CustomerID

答案 2 :(得分:4)

我不清楚为什么您将Customers和Contacts定义为单独的实体,而它们似乎是同一实体的版本。在我看来,客户是其他信息的联系人。如果可能的话,我会创建一个Contacts表,然后使用该表中的字段标记Customer的表,或者将其id添加到表中具有扩展单例客户信息的客户。

如果你不能这样做(因为这是建立在现有系统之上,其设计是固定的)那么你有几个选择。没有一个选择是好的,因为它们无法真正解决原始缺陷,即分别存储客户和联系人。

  1. 使用两列,一个NULL,以使参照完整性起作用。

  2. 使用自己的PK和两列(一个NULL)构建一个中间表ActivityContacts,以指向Customer或Contact。这允许您构建一个“干净”的Activity系统,但将丑陋推入该中间表。 (它确实提供了一个可能的好处,即它允许您将活动目标限制为添加到中间表的人员,如果这对您有利)。

  3. 将原始设计缺陷带入活动系统,(我在这里咬我的舌头)有并行的ContactActivity和CustomerActivity表。要查找员工分配的所有任务,请将这两个表一起UNATION到一个VIEW中。这使您可以保持参照完整性,不需要NULL列,并为您提供获取报告的来源。

答案 3 :(得分:2)

这是我的抨击:

基本上,您需要与1(联系人或客户)和1名员工相关联的活动,该员工将成为活动的负责人。请注意,您可以在这样的模型中处理引用约束。

另请注意,我添加了一个连接所有人员和地点的businessEntity表。 (有时有用但不必要)。放置businessEntity表的原因是您可以简单地将活动的ResponsiblePerson和Recipient引用到businessEntity,现在您可以让任何人或所有人或地方执行和接收活动。

alt text

答案 4 :(得分:2)

如果我已经正确阅读了案例,则收件人是客户和联系人的概括 gen-spec设计模式很好理解。

Data modeling question

答案 5 :(得分:1)

您将拥有以下内容:

Activity | Description | Recipient Type

其中Recipient TypeContactCustomer

之一

然后执行SQL select语句,如下所示:
Select * from table where Recipient_Type = 'Contact';

我意识到需要更多信息。

我们需要一个代表收件人(联系人和客户)的附加表:

此表格如下所示:

ID | Name| Recipient Type

Recipient Type将是本文前面提到的表格的关键参考。当然,需要完成工作来处理这些表中的级联,主要是更新和删除。所以要快速回顾一下:

Recipients.Recipient_TypeTable.Recipient_Type

的FK

答案 6 :(得分:1)

alt text

答案 7 :(得分:0)

    [ActivityRecipientRecipientType]
    ActivityId
    RecipientId
    RecipientTypeCode
        |||   |||  |||_____________________________    
         |     |                                  |
         |     --------------------               |
         |                        |               |
    [Activity]                [Recipient]      [RecipientType]
    ActivityId                RecipientId      RecipientTypeCode
    ActivityDescription       RecipientName    RecipeintTypeName


    select 
      [Activity].ActivityDescription  
    , [Recipient].RecipientName
    from
      [Activity] 
  join [ActivityRecipientRecipientType] on [Activity].ActivityId = [ActivityRecipientRecipientType].ActivityId
  join [Recipient] on [ActivityRecipientRecipientType].RecipientId = [Recipient].RecipientId
  join [RecipientType] on [ActivityRecipientRecipientType].RecipientTypeCode = [RecipientType].RecipientTypeCode
  where [RecipientType].RecipientTypeName = 'Contact'

答案 8 :(得分:0)

Actions
Activity_ID | Description | Recipient ID
-------------------------------------
11    | Don't ask questions | 0
12    | Be cool    | 1

Activities
ID | Description
----------------
11  | Shoot
12  | Ask out

People
ID | Type | email | phone | GPS |....
-------------------------------------
0  | Troll | troll@hotmail.com | 232323 | null | ...
1  | hottie | hottie@hotmail.com | 2341241 | null | ...


select at.description,a.description, p.* from Activities at, Actions a, People p
where a."Recipient ID" = p.ID 
  and at.ID=a.activity_id

result:

Shoot | Don't ask questions | 0 | Troll | troll@hotmail.com | 232323 | null | ...  
Ask out | Be cool | 1 | hottie | hottie@hotmail.com | 2341241 |null | ...

答案 9 :(得分:0)

建模另一个实体:ActivityRecipient,它将由ActivityRecipientContact和ActivityRecipientCustomer继承,它将保留正确的客户/联系人ID。

相应的表格将是:

Table: Activities(...., RecipientID)

Table: ActivityRecipients(RecipientID, RecipientType)

Table: ActivityRecipientContacts(RecipientID, ContactId, ...,ExtraContactInfo...)

Table: ActivityRecipientCustomers(RecipentID, CustomerId, ...,ExtraCustomerInfo...)

这样,您还可以为每个收件人类型添加不同的其他列

答案 10 :(得分:0)

我会修改客户和联系人的定义。客户既可以是个人也可以是企业,对吧?在巴西,有“pessoajurídica”和“pessoafísica”这两个术语 - 在直接(和无意识)翻译中成为“法人”(商业)和“自然人”(个人)。谷歌提出了一个更好的翻译:“法人实体”和“个人”。

所以,我们得到一个人员表,并有一个'LegalEntity'和'Individual'表(如果有足够的属性来证明它 - 这里有很多)。接收器成为FK到Person表。

联系方式已经消失了?他们成为一个与人相关的桌子。由于联系人是与他人联系的人(例如:我的妻子是我与某些公司的注册联系人,我是客户)。人们可以有联系。

注意:我使用了“Person”这个词,但您可以将其命名为“Customer”来命名该基表。