【问题标题】:Relating a child table to multiple parent tables将子表关联到多个父表
【发布时间】:2013-12-13 00:33:39
【问题描述】:

我正在尝试找出将这些表关联在一起的最佳方式。假设我有以下表格:

  • tblPerson
  • tbl 组
  • tbl资源

每个表格中的每一行都可以有多个与之关联的电子邮件地址,因此我想要一个单独的表格并将其关联回来。

是否有方法让单个表 (tblEmail) 与每个表相关联。我想在每个父表中使用一个 uniqueidentifier 字段,并将其用作电子邮件表中的键。它将保证是独一无二的。我只是无法在电子邮件表中创建 FK 以保持完整性。不过这是可以管理的。

有什么奇特的方法可以做到这一点吗?我正在 SQL 2008 R2 中创建这些表。

谢谢 卡尔

【问题讨论】:

  • 您希望每个人/组/资源记录有很多电子邮件记录,我得到了这么多。您是否也想在人/组/资源之间建立某种关系,如果是的话,它是否与电子邮件有关?
  • 不太确定我是否关注你。父表之间会有一些关系,例如资源可以由一个人(或多个人)拥有。电子邮件更多是每个父表项都可以拥有的属性。

标签: sql-server tsql


【解决方案1】:

虽然尝试使用带有ParentType(个人/组/资源)和ParentID 的单个电子邮件表可能很诱人,但这很危险,意味着您不能在 SQL 中定义关系(除非有一些我不知道的功能?)。

如果您想在 SQL 中具有参照完整性,您确实需要创建 3 个表,每个父表一个。

CREATE TABLE dbo.PersonEmail (
    ID int IDENTITY PRIMARY KEY,
    PersonID int,
    EmailAddress varchar(500)
)

CREATE TABLE dbo.GroupEmail (
    ID int IDENTITY PRIMARY KEY,
    GroupID int,
    EmailAddress varchar(500)
)

CREATE TABLE dbo.ResourceEmail (
    ID int IDENTITY PRIMARY KEY,
    ResourceID int,
    EmailAddress varchar(500)
)

如果您认为以后可能会扩展您的电子邮件表以包含 DisplayName、可能还有 BounceCount 等,请为电子邮件创建一个表并创建多对多连接表以将它们链接到个人/组/资源。

请注意,编辑可能会影响多个链接,您必须决定如何处理。

【讨论】:

  • 使用单个 tblEmail 指定的 OP。只需创建三个表作为 Person/Group/Resource 表和 Email 表之间的交叉引用,它应该满足他们的要求。它确实引出了处理共享或重复电子邮件地址的问题。
  • @HABO 正如我在 SQL 脚本之后的评论中提到的,有一个 tblEmail 是一个选项,但需要 3 个连接表(多对多)。我自己更喜欢这个选项,以允许电子邮件表的未来增长,但在我的答案的第一部分提出了一个更简单的选项。
  • 所以,这是我的想法,但它想要一张桌子。这既简单又合理,我可以在视图中加入单独的电子邮件表。问题可能是重复的电子邮件,但我可以在代码中处理。如果我稍微重新组织我的父表,我可能会走这条路,也许是按系统而不是角色来组织。
【解决方案2】:

这是 SQL 的核心部分。在适当的关系设计中,您不会将电子邮件地址与人员、组或资源相关联——您将人员、组和资源与电子邮件相关联。

所以,有一个电子邮件表:

CREATE TABLE dbo.tblEmail (
  emailID int IDENTITY PRIMARY KEY,
  email varchar(500)
)

如果您只需要每个实体一封电子邮件,您只需在其他每个字段中插入一个emailID,以模拟可能需要电子邮件的内容。

ALTER TABLE dbo.tblPerson
ADD emailID int REFERENCES dbo.tblEmail(emailID);

ALTER TABLE dbo.tblGroup
ADD emailID int REFERENCES dbo.tblEmail(emailID);

ALTER TABLE dbo.tblResource
ADD emailID int REFERENCES dbo.tblEmail(emailID);

如果您需要每个实体多个 电子邮件地址,您需要插入一个附加表,以将一组电子邮件地址插入到特定地址。 (我不会这样做,除非您有单独处理地址的技术原因,例如批量电子邮件系统,如果有人将同一电子邮件用于自己和组织的使用,您希望在该系统中避免重复。)

CREATE TABLE dbo.tblEmail (
  emailID int IDENTITY PRIMARY KEY
)

CREATE TABLE dbo.tblEmailAddress (
  eAddrID IDENTITY PRIMARY KEY,
  eAddr varchar(500)
)

CREATE TABLE dbo.tblEmailSet (
  emailID int REFERENCES dbo.tblEmail(emailID),
  eAddrID int REFERENCES dbo.tblEmailAddresses(eAddrID),
)

例如,为了将所有电子邮件列表返回给名为“Smith”的任何个人、组或资源,您需要运行以下查询:

SELECT DISTINCT A.eAddr
FROM (
  SELECT emailID FROM dbo.tblPerson WHERE Name = 'Smith'
  UNION
  SELECT emailID FROM dbo.tblGroup WHERE Name = 'Smith'
  UNION
  SELECT emailID FROM dbo.tblResource WHERE Name = 'Smith'
) AS PGR
INNER JOIN dbo.tblEmailSet AS S
  ON PGR.emailID = S.emailID
INNER JOIN dbo.tblEmailAddress AS A
  ON S.eAddrID = A.eAddrID

那个丑陋的UNION,顺便说一句,是你真的不想这样做的原因之一,除非你有技术需要来唯一地检索数据。虽然我有时会执行这种多对多对多的连接,但在这种特殊情况下,它有点像“代码味道”,并且是一个指示符,而不是跟踪“人”、“组”和“资源”,您应该使用“类型”指示器跟踪“联系人”,以判断联系人是人员、组还是资源。

(或者也许您永远不需要获取一堆电子邮件地址,而只需要一个可以检查白名单的电子邮件表......)

【讨论】:

  • 而且,作为一个让我发疯的挑剔——不要对数据库名称使用匈牙利符号!当然,“dbo.tblGroup”是一个表NOW,但如果它只是“dbo.Group”,您可以在适当的情况下将其重构为视图或 TBF,而不会破坏您的名称。跨度>
  • 感谢您的回复!这只允许我为每个人/组/资源拥有一个电子邮件地址。我需要能够拥有多个电子邮件地址。
【解决方案3】:

所以您希望每个人/组/资源可能有多个电子邮件,并且您希望将所有这些电子邮件放在一个表中,对吗?

为此,我将创建一个表 dbo.EmailAddress,如下所示:

CREATE TABLE dbo.EmailAddress 
(
   EmailID BIGINT IDENTITY(1,1)  NOT NULL PRIMARY KEY
   ,EmailAddress VARCHAR(250) NOT NULL

   CONSTRAINT UK_EmailAddress UNIQUE(EmailAddress) --to ensure that you never insert twice the same email address
)

然后我将使用另一个表创建您的人员/组/资源和您的电子邮件之间的关系:

CREATE TABLE dbo.EmailAddressParentXRef
(
    EmailID INT NOT NULL REFERENCES dbo.EmailAddress(EmailID)
    ,ParentTypeID INT NOT NULL
    ,PersonID INT NULL REFERENCES dbo.tblPerson(PersonID)
    ,GroupID INT NULL REFERENCES dbo.tblGroup(GroupID)
    ,ResourceID INT NULL REFERENCES dbo.tblResource(ResourceID)

    CONSTRAINT UK_EmailID_ParentTypeID UNIQUE(EmailID,ParentTypeID) --to make sure you don't put the same EmailID for the same type of Parent (e.g. EmailID=12 twice for an Account)
)

在那里,您将在加载数据时进行引用完整性+一些检查以避免重复。请注意,我没有检查以确保您确实填写了 PersonID、GroupID 或 ResourceID。这可以通过不同的方式添加,但是如果您了解此表的原理,则不应加载没有这些引用的任何行(否则它们将毫无用处)。

可以基于此添加更多检查,以处理您在加载数据时可能创建的每种类型的重复/错误,但您明白了。

【讨论】:

  • 外部参照表的架构表明,在“board.room@mycompany.com”和资源“Board Room”之间添加链接需要我还必须将其链接到 Person 和一个组(因为它们不允许 NULL),但这样的电子邮件可能没有人员/组。
  • 我知道你在做什么。但是,正如 Timothy 所提到的,您不能对所有三个父表都有 FK。相同的电子邮件永远不会存在于所有三个表中。删除约束并允许 NULL 然后它会起作用,只是在 SQL 级别上没有完整性。
  • 你们是对的,那些应该是可空的,我以为我已经纠正了,所以我的错误。不过,您仍然可以保留 Fks,因为它们只是强制它们引用的表包含任何值(但不是 NULL)。这样你仍然有你想要的完整性(或者我可能遗漏了什么?)。
猜你喜欢
  • 2015-04-15
  • 2019-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多