将子表关联到多个父表

时间:2013-12-13 00:33:40

标签: sql-server tsql

我试图找出将这些表联系在一起的最佳方法。假设我有以下表格:

  • tblPerson
  • tblGroup
  • tblResource

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

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

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

谢谢 卡尔

4 个答案:

答案 0 :(得分: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,顺便说一句,这是你真的不想这样做的原因之一,除非你有技术上需要唯一地检索数据。虽然我偶尔会做这种多对多的连接,但在这个特殊情况下,它有点像“代码味道”,而不是跟踪“人物”,“群组”和“资源“,您应该使用”类型“指示符跟踪”联系人“,以告知联系人是个人,组还是资源。

(或者你可能永远不需要抓住一堆电子邮件地址,只需要一张电子邮件表就可以检查白名单......)

答案 1 :(得分:0)

虽然尝试使用带有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和其他人,请为电子邮件创建一个表并创建多对多连接表以将其链接到人员/组/资源。

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

答案 2 :(得分:0)

因此,您希望每个人/组/资源可能有多个电子邮件,并且您希望将所有这些电子邮件放在一个表中,我是否正确?

为此,我将创建一个表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。这可以以不同的方式添加,但是如果你理解了这个表的原理,你就不应该加载没有那些引用的任何行(或者它们只是没用)。

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

答案 3 :(得分:0)

Each row in each of these tables can have multiple email addresses associated with them

你能给出每个表的一个例子吗。电子邮件是多个?