我们可以在一个外键字段中有两个主键吗?

时间:2014-04-25 08:42:38

标签: sql-server database database-design

我的数据库层次结构就像是Group - >分支 - >部门。 Employee和Roles是不同的表,tbl_Employee具有FK groupid,branchid,departmentid和RoleId。如果我将员工指定为' 1'根据Roles表,这是一个groupHead,那么我必须提供这个员工的branchId和depId。但特定群体的所有分支都属于他。所以我在考虑写下他身下的所有branchIds。我该怎么办?

1 个答案:

答案 0 :(得分:1)

您可以构建这样的结构:

create table Groups (
    GroupID char(2) not null primary key
)
create table Branches (
    GroupID char(2) not null foreign key references Groups (GroupID),
    BranchID char(2) not null primary key,
    constraint UQ_Branch_XRef UNIQUE (GroupID,BranchID)
)
create table Departments (
    GroupID char(2) not null foreign key references Groups (GroupID),
    BranchID char(2) not null foreign key references Branches (BranchID),
    DepartmentID char(2) not null primary key,
    constraint UQ_Department_XRef UNIQUE (GroupID,BranchID,DepartmentID),
    constraint FK_Department_Branch_XRef FOREIGN KEY (GroupID,BranchID)
        references Branches (GroupID,BranchID)
)
create table Employees (
    EmployeeID char(2) not null primary key,
    GroupID char(2) not null references Groups (GroupID),
    BranchID char(2) null references Branches (BranchID),
    DepartmentID char(2) null references Departments (DepartmentID),
    RoleID int not null,
    constraint FK_Employee_Branch_XRef FOREIGN KEY (GroupID,BranchID)
        references Branches (GroupID,BranchID),
    constraint FK_Employee_Department_XRef FOREIGN KEY (GroupID,BranchID,
                                                        DepartmentID) 
        references Departments (GroupID,BranchID,DepartmentID),
    constraint CK_AppropriateRole CHECK (
        (RoleID = 1 and BranchID is null and DepartmentID is null) or
        (RoleID = 2 and BranchID is not null and DepartmentID is null) or
        (RoleID = 3 and BranchID is not null and DepartmentID is not null)
    )
)

然后像这样填充它:

insert into Groups (GroupID) values ('aa'),('bb')
insert into Branches (GroupID,BranchID) values
('aa','cc'),('aa','dd'),('bb','ee'),('bb','ff')
insert into Departments (GroupID,BranchID,DepartmentID) values
('aa','cc','gg'),
('aa','cc','hh'),
('aa','dd','ii'),
('bb','ee','jj'),
('bb','ff','kk'),
('bb','ff','ll')

并插入一些有效的员工

insert into Employees (EmployeeID,GroupID,BranchID,DepartmentID,RoleID) values
('mm','aa',null,null,1),
('nn','aa','dd',null,2),
('oo','bb','ee','jj',3)

但是你不能插入无效的行:

insert into Employees (EmployeeID,GroupID,BranchID,DepartmentID,RoleID) values
('pp','bb',null,null,3)
insert into Employees (EmployeeID,GroupID,BranchID,DepartmentID,RoleID) values
('qq','aa','cc','hh',1)
insert into Employees (EmployeeID,GroupID,BranchID,DepartmentID,RoleID) values
('rr','aa','cc','ii',3)

然后暗示'mm'附加到群组'aa',其下的所有分支机构和部门'nn'都附加到群组'dd'的分支'aa' }以及其下的所有部门,'oo'位于组'jj'的分支'ee'的部门'bb'


每当您在SQL Server中的外键(一列)中存储NULL时,SQL Server都不会强制执行该外键。


约束

上述4个表中有16个约束,其中大多数都有重要作用。我会忽略主键,因为它们只是履行了他们通常的角色。

create table Branches (
    GroupID char(2) not null foreign key references Groups (GroupID),

只是一个简单的外键。没什么特别的

    ...
    constraint UQ_Branch_XRef UNIQUE (GroupID,BranchID)

我们需要这个唯一约束,以便外键可以通过两列引用此表,以便我们可以交叉检查使用BranchID的位置,它与正确一起使用GroupID

)
create table Departments (
    GroupID char(2) not null foreign key references Groups (GroupID),
    BranchID char(2) not null foreign key references Branches (BranchID),

上述两个外键引用并非绝对必要。此表中下面定义的另一个FK也将确保这些值有效。但它们是大多数人所定义的“自然”FK。无论你是否保留它们都是一种偏好和可能的表现。

    ...
    constraint UQ_Department_XRef UNIQUE (GroupID,BranchID,DepartmentID),

这与上面UQ_Branch_XRef的角色类似,允许FK通过所有3列引用此表,以确保所有值都一致。

    constraint FK_Department_Branch_XRef FOREIGN KEY (GroupID,BranchID)
        references Branches (GroupID,BranchID)

这是第一个使用UQ_Branch_XRef的FK,确保我们的GroupID列适合我们选择的BranchID

)

create table Employees (
    ...
    GroupID char(2) not null references Groups (GroupID),

如果BranchIDDepartmentID都为空,则此FK约束很重要 - 这是我们在这种情况下实际应用的唯一FK约束。

    BranchID char(2) null references Branches (BranchID),
    DepartmentID char(2) null references Departments (DepartmentID),

这两个FK在技术上是多余的,考虑到下面宣布的其他FK,但它们是“自然的”FK。

    ...
    constraint FK_Employee_Branch_XRef FOREIGN KEY (GroupID,BranchID)
        references Branches (GroupID,BranchID),

这可确保我们的GroupIDBranchID正确无误。只有当DepartmentID为空时,此FK才重要,因为在这种情况下,下一个FK将不会应用约束

    constraint FK_Employee_Department_XRef FOREIGN KEY (GroupID,BranchID,
                                                        DepartmentID) 
        references Departments (GroupID,BranchID,DepartmentID),

这是一个约束,可确保所有3个命名列与Departments表中的条目匹配。

    constraint CK_AppropriateRole CHECK (
        (RoleID = 1 and BranchID is null and DepartmentID is null) or
        (RoleID = 2 and BranchID is not null and DepartmentID is null) or
        (RoleID = 3 and BranchID is not null and DepartmentID is not null)
    )

最后,这是一个约束,它应用了一些关于哪些角色应填入哪些角色的业务规则。

)