这是一个令我们困惑的棘手的规范化/ SQL /数据库设计问题。我希望我能正确说明。
您有一系列活动。他们是需要做的事情 - 一个荣耀的TODO清单。任何给定的活动都可以分配给员工。
每项活动也都有活动进行的活动。这些活动是联系人(个人)或客户(业务)。然后,每个活动都将有一个联系人或一个将为其开展活动的客户。例如,活动可能是“向Spacely Sprockets(客户)发送感谢卡”或“向Tony Almeida发送营销资料(联系人)”。
从那个结构中,我们需要能够查询以查找给定员工必须完成的所有活动,将它们列在一个最简单形式的单一关系中:
-----------------------------------------------------
| Activity | Description | Recipient of Activity |
-----------------------------------------------------
这里的想法是避免为Contact和Customer提供两列null,其中一列为null。
我希望我已经正确地描述了这一点,因为这并不像乍看之下那么明显。
所以问题是:数据库的“正确”设计是什么?如何查询它以获取所要求的信息?
答案 0 :(得分:9)
这听起来像是一个基本的多对多关系,我会这样建模。
答案 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添加到表中具有扩展单例客户信息的客户。
如果你不能这样做(因为这是建立在现有系统之上,其设计是固定的)那么你有几个选择。没有一个选择是好的,因为它们无法真正解决原始缺陷,即分别存储客户和联系人。
使用两列,一个NULL,以使参照完整性起作用。
使用自己的PK和两列(一个NULL)构建一个中间表ActivityContacts,以指向Customer或Contact。这允许您构建一个“干净”的Activity系统,但将丑陋推入该中间表。 (它确实提供了一个可能的好处,即它允许您将活动目标限制为添加到中间表的人员,如果这对您有利)。
将原始设计缺陷带入活动系统,(我在这里咬我的舌头)有并行的ContactActivity和CustomerActivity表。要查找员工分配的所有任务,请将这两个表一起UNATION到一个VIEW中。这使您可以保持参照完整性,不需要NULL列,并为您提供获取报告的来源。
答案 3 :(得分:2)
这是我的抨击:
基本上,您需要与1(联系人或客户)和1名员工相关联的活动,该员工将成为活动的负责人。请注意,您可以在这样的模型中处理引用约束。
另请注意,我添加了一个连接所有人员和地点的businessEntity表。 (有时有用但不必要)。放置businessEntity表的原因是您可以简单地将活动的ResponsiblePerson和Recipient引用到businessEntity,现在您可以让任何人或所有人或地方执行和接收活动。
答案 4 :(得分:2)
如果我已经正确阅读了案例,则收件人是客户和联系人的概括 gen-spec设计模式很好理解。
答案 5 :(得分:1)
您将拥有以下内容:
Activity | Description | Recipient Type
其中Recipient Type
是Contact
或Customer
然后执行SQL select语句,如下所示:
Select * from table where Recipient_Type = 'Contact';
我意识到需要更多信息。
我们需要一个代表收件人(联系人和客户)的附加表:
此表格如下所示:
ID | Name| Recipient Type
Recipient Type
将是本文前面提到的表格的关键参考。当然,需要完成工作来处理这些表中的级联,主要是更新和删除。所以要快速回顾一下:
Recipients.Recipient_Type
是Table.Recipient_Type
答案 6 :(得分:1)
答案 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”来命名该基表。