无法从单个主键表中制作多个外键

时间:2019-11-10 13:26:31

标签: sql sql-server

这是我正在尝试执行的操作,但是sql不允许我这样做。如果无法实现,请给我建议替代方法。

enter image description here

2 个答案:

答案 0 :(得分:1)

您想要的肯定可以实现。请考虑以下表定义:

create table Tbl_Course(
    CrsId int primary key, 
    CrsName varchar(100)
);

create table Tbl_Student(
    StdId int primary key,
    StdCourse1 int,
    StdCourse2 int,
    StdCourse3 int,
    foreign key (StdCourse1) references Tbl_Course(CrsId),
    foreign key (StdCourse2) references Tbl_Course(CrsId),
    foreign key (StdCourse3) references Tbl_Course(CrsId)
);

完成此设置后,您可以插入示例数据:

insert into Tbl_Course values
    (1001, 'MATHS'),
    (1002, 'PHYSICS'),
    (1003, 'CHEMISTRY'),
    (1004, 'ARTS');

insert into Tbl_Student values
    (1, 1001, 1002, 1003),
    (2, 1002, 1003, 1004),
    (3, 1004, null, null);

如果您尝试在子表中插入父表中不存在的值,则会出现错误:

insert into Tbl_Student values(4, 1005, null, null);
  

INSERT语句与FOREIGN KEY约束“ FK__Tbl_Stude__StdCo__38996AB5”发生冲突

但是应注意,表Tbl_Student的设计未规范化。如果学生参加超过3门课程怎么办?您将需要向表中添加更多列。您如何检查用户是否参加了给定的课程?您需要签入3个不同的列。对于遵循标准规范化规则的替代设计,请参见Dai的以下答案。

答案 1 :(得分:1)

Your design is not correctly normalized。不要使用列来表达多个关系,而要使用行。

此外,匈牙利表示法也皱了皱眉。避免使用对象标识符前缀,例如“ Tbl_”。无需在列名中使用缩写。在可能的情况下,请始终使用完整的拼写,以便其他人可以理解您的系统(又称“自记录代码”)。

考虑这样的设计:

CREATE TABLE Students (
    StudentId int NOT NULL PRIMARY KEY IDENTIY(1,1),
    -- etc
)

CREATE TABLE Courses (
    CourseId int NOT NULL PRIMARY KEY IDENTIY(1,1),
    Name nvarchar(100) NOT NULL,
    -- etc
)

CREATE TABLE StudentsInCourses (
    StudentId int NOT NULL PRIMARY KEY, -- Composite primary key
    CourseId int NOT NULL PRIMARY KEY,

    CONSTRAINT FOREIGN KEY ( StudentId ) REFERENCES Students ( StudentId ),
    CONSTRAINT FOREIGN KEY ( CourseId ) REFERENCES Courses ( CourseId )
)

此设计允许学生无限制地参加零个或多个课程,并允许使用JOIN and other relational operators直接查询在校学生关系,而您的设计却没有如果学生要学习三门以上的课程,或者您要运行涉及某个课程的学生的查询,而该课程可以是Course1Course2或{{1} }。

此外,由于两列都参与Course3中的复合主键,因此该设计使学生不可能多次参加同一课程(如果不希望这样做,请使用更具体的要求)