外键在PostgreSQL中引用其他外键

时间:2014-08-21 15:37:22

标签: sql postgresql database-design foreign-keys

在PostgreSQL中我有一个数据库,我打算做下面的表声明:

CREATE TABLE canvas_user (
    id INTEGER,
    login_id VARCHAR(50) UNIQUE NOT NULL,
    email VARCHAR(355) UNIQUE NOT NULL,
    name_given VARCHAR(30),
    name_family VARCHAR(30),
    name_full VARCHAR(50),
    role canvas_role,
    last_login TIMESTAMP,
    PRIMARY KEY (id)
);

CREATE TABLE problem (
    id SERIAL,
    title VARCHAR(50),
    author VARCHAR(50),
    path TEXT,
    compiler VARCHAR(20),
    PRIMARY KEY (id)
);

CREATE TABLE assignment (
    id INTEGER,
    title TEXT NOT NULL,
    points_possible INTEGER NOT NULL,
    problem_id INTEGER,
    PRIMARY KEY (id),
    FOREIGN KEY (problem_id) REFERENCES problem(id)
);

CREATE TABLE submission (
    num SERIAL,
    user_id INTEGER,
    assignment_id INTEGER,
    timestamp TIMESTAMP,
    path TEXT,
    lti_info TEXT[],
    PRIMARY KEY(num, user_id, assignment_id),
    FOREIGN KEY (user_id) REFERENCES canvas_user(id),
    FOREIGN KEY (assignment_id) REFERENCES assignment(id)
);

CREATE TABLE correction (
    num INTEGER,
    user_id INTEGER,
    assignment_id INTEGER,
    timestamp TIMESTAMP,
    path TEXT,
    execution_time interval,
    PRIMARY KEY(num, user_id, assignment_id),
    FOREIGN KEY (num) REFERENCES submission(num),
    FOREIGN KEY (user_id) REFERENCES submission(user_id),
    FOREIGN KEY (assignment_id) REFERENCES submission(assignment_id)
);

一切正常,除了在创建最后一个表时出现以下错误(更正):

  

错误:没有与给定键匹配的唯一约束   参考表"提交"

我打算使用更正表来对每次提交进行唯一更正,但提交内容可以进行(或不进行)更正。

如何解决此错误?是设计问题还是表格声明错误?

2 个答案:

答案 0 :(得分:4)

外键约束不关心引用的列是否引用另一列本身。但引用的列必须是唯一的。这是错误信息告诉你的内容(非常清楚)。

你缺少的是foreign key constraint can be based on multiple columns。这应该有效:

FOREIGN KEY (num, user_id, assignment_id) REFERENCES submission

更换:

FOREIGN KEY (num) REFERENCES submission(num),
FOREIGN KEY (user_id) REFERENCES submission(user_id),
FOREIGN KEY (assignment_id) REFERENCES submission(assignment_id)

语法的简短形式(REFERENCES submission)是可能的,因为您正在引用主键,这是默认值。

另外,您可以简化:使submission.num sinlge-column主键,从user_id删除冗余列assignment_idcorrection,并将fk约束减少为just (num) - 正如@Tim's answer中所述。

只要您具有多列fk约束,请考虑每个引用列的NOT NULL约束(由@joop注释)。否则,引用列中的一个或多个NULL值允许使用默认的MATCH SIMPLE行为转义fk约束。这可能是也可能不是,通常是 或者,对多列fk约束考虑MATCH FULL,只允许所有引用列为NULL。详细说明:

答案 1 :(得分:3)

将修改表中的外键设置为提交表,这是一个唯一的复合键。 另外,审查提交表的设计; num是一个串行类型,应该是唯一的主键。您可以向列num,user_id和assignment_id

添加唯一约束
CREATE TABLE canvas_user (
    id INTEGER,
    login_id VARCHAR(50) UNIQUE NOT NULL,
    email VARCHAR(355) UNIQUE NOT NULL,
    name_given VARCHAR(30),
    name_family VARCHAR(30),
    name_full VARCHAR(50),
    role canvas_role,
    last_login TIMESTAMP,
    PRIMARY KEY (id)
);


CREATE TABLE problem (
    id SERIAL,
    title VARCHAR(50),
    author VARCHAR(50),
    path TEXT,
    compiler VARCHAR(20),
    PRIMARY KEY (id)
);


CREATE TABLE assignment (
    id INTEGER,
    title TEXT NOT NULL,
    points_possible INTEGER NOT NULL,
    problem_id INTEGER,
    PRIMARY KEY (id),
    FOREIGN KEY (problem_id) REFERENCES problem(id)
);


CREATE TABLE submission (
    num SERIAL,
    user_id INTEGER,
    assignment_id INTEGER,
    timestamp TIMESTAMP,
    path TEXT,
    lti_info TEXT[],
    PRIMARY KEY(num, user_id, assignment_id),
    FOREIGN KEY (user_id) REFERENCES canvas_user(id),
    FOREIGN KEY (assignment_id) REFERENCES assignment(id)
);


CREATE TABLE correction (
    num INTEGER,
    user_id INTEGER,
    assignment_id INTEGER,
    timestamp TIMESTAMP,
    path TEXT,
    execution_time interval,
    PRIMARY KEY(num, user_id, assignment_id),
    FOREIGN KEY (num, user_id,assignment_id ) REFERENCES submission(num, user_id, assignment_id)

);