数据库设计-多个外键

时间:2019-10-09 22:30:58

标签: mysql sql database orm

我的数据库包含学校,部门和课程。学校可能有也可能没有部门,并且课程与学校有关,也可能与部门无关(学校可能没有部门,或者课程可能是跨部门的)

我的表当前设置如下:

school

ID       | name
--------------------
harvard  | Harvard University
mit      | MIT
ucla     | UCLA

division(id + school = unique)

ID  | school (FK) | name
------------------------------------------
eng | harvard     | School of Engineering
arc | harvard     | School of Architecture
eng | UCLA        | UCLA Engineering

course

ID | school (FK) | division | name
-------------------------------------------------
1  | harvard     | eng      | Intro to Engineering 
2  | harvard     | arc      | Intro to Architecture
3  | harvard     |          | Statistics
4  | mit         |          | Math

我对此表示关注:

  • 没有验证来确保course中的部门存在并且与学校有关。
  • 除法实际上不是fk
  • 需要两个查询才能获得学校和部门

是否有更好的方法?我希望能够:

  • 查询所有“哈佛”课程
  • 查询所有“哈佛工程”课程
  • 查询所有“哈佛工程与哈佛一般”课程

2 个答案:

答案 0 :(得分:0)

您可以创建一个多列外键:

CREATE TABLE course (
    id INT(11) AUTO_INCREMENT PRIMARY KEY,
    school VARCHAR(50),
    division VARCHAR(50),
    name VARCHAR(50),
    FOREIGN KEY (school, division) REFERENCES division(school, id)
);

但是,最好在AUTO_INCREMENT表中使用单独的division列,并将其用作外键。这样,您不必在course表中重复两列。

CREATE TABLE division (
    id INT(11) AUTO_INCREMENT PRIMARY KEY,
    division_code VARCHAR(50),
    school VARCHAR(50),
    name VARCHAR(50),
    UNIQUE KEY (division_code, school),
    FOREIGN KEY (school) REFERENCES school (id)
);
CREATE TABLE course (
    id INT(11) AUTO_INCREMENT PRIMARY KEY,
    division_id INT(11),
    name VARCHAR(50),
    FOREIGN KEY (division_id) REFERENCES division(id)
);

答案 1 :(得分:0)

如果始终可以创建复合外键。但是,我建议对您的设计进行以下更改:

  • 为每所学校创建一个默认的部门,称为“常规”
  • 允许同一门课程在不同的学校开设(在现实生活中可能会发生)。

我也建议对所有表使用自动递增的整数主键,而不要依赖手工构建的名称。

请考虑遵循上述原则的以下设计:

school
    id            primary key
    name

division
    id            primary key
    school_id     foreign key to school(id)
    name

course
    id            primary key
    name

course_division
    id            primary key
    course_id     foreign key to course(id)
    division_id   foreign key to course(id)

现在是使用此架构的查询。

查询所有“哈佛”课程

SELECT c.* 
FROM course c
INNER JOIN division d ON d.id = cd.division_id
INNER JOIN school s ON s.id = d.school_id AND s.name = 'Harvard University'

查询所有“哈佛工程”课程

SELECT c.* 
FROM course c
INNER JOIN course_division cd ON cd.id = c.course_id 
INNER JOIN division d ON d.id = cd.division_id AND d.name = 'School of Engineering'
INNER JOIN school s ON s.id = d.school_id AND s.name = 'Harvard University'

查询所有“哈佛工程和哈佛一般”课程

SELECT c.* 
FROM course c
INNER JOIN course_division cd ON cd.id = c.course_id 
INNER JOIN division d ON d.id = cd.division_id AND d.name IN ('School of Engineering', 'General')
INNER JOIN school s ON s.id = d.school_id AND s.name = 'Harvard University'