【问题标题】:Foreign keys referring other foreign keys in PostgreSQL外键引用 PostgreSQL 中的其他外键
【发布时间】:2014-10-15 07:51:34
【问题描述】:

在 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)
);

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

错误:没有与给定键匹配的唯一约束 引用表“提交”

我打算使用更正表对每个提交进行唯一的更正,但提交可以有(或没有)更正。

我该如何解决这个错误?是设计问题还是表声明错误?

【问题讨论】:

  • 在提交表时给 user_id 和 assignment_id 添加 NOT NULL。((复合)主键的所有元素都必须是 NOT NULLable)
  • @otorillas: 你为什么不在DDL 语句中为你的numuser_idassignment_id 属性定义一个多列外键约束@​​987654326@像这样的表:FOREIGN KEY(num, user_id, assignment_id) REFERENCES submission(num, user_id, assignment_id)?编辑:请原谅,@ErwinBrandstetter 似乎已经用更彻底的答案击败了我。 :)
  • 糟糕,滚动失败,没有看到更正表。不过,仍然需要 NOT NULL。
  • @joop:我倾向于同意,但还有更多。我在答案中添加了一章。

标签: sql postgresql database-design foreign-keys


【解决方案1】:

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

您缺少的是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 设为单列主键,从correction 中删除冗余列user_idassignment_id,并将fk 约束减少到仅(num) - 如@ 中所述987654322@。

只要您有多列 fk 约束,请考虑每个引用列上的 NOT NULL 约束(由 @joop 评论)。否则,引用列中的一个或多个 NULL 值允许使用默认的 MATCH SIMPLE 行为来转义 fk 约束。这可能是有意的,也可能不是有意的,通常是
或者,考虑MATCH FULL 用于多列 fk 约束,仅在 all 引用列为 NULL 时允许。详情:

【讨论】:

  • 谢谢,成功了!我首先尝试这样做: FOREIGN KEY (num, user_id, assignment_id) REFERENCES submit(num, user_id, assignment_id) 但没有成功。
  • @otorrillas:嗯...约束定义应该是有效的。检查您的语句是否有任何意外的语法错误(但请记住,Erwin Branstetter 的较短形式看起来更优雅)。
  • @otorrillas:这一次,Priidu 打败了我,我正要发表同样的评论。为了清楚起见,显式形式甚至可能更可取。
  • 感谢两位提供如此大的帮助。
  • 我明白你的观点@ErwinBrandstetter,但在我的特殊情况下,有两点我想说明:-Assignment_id 和 user_id 永远不会为空,因为它是提交特定内容的用户问题,因此在上传提交之前它们必须存在。 - 我不想只将 submit.num 设为 PK,因为我要存储的是用户针对特定问题提交的数量。
【解决方案2】:

使更正表到提交表的外键成为唯一的复合键。 此外,审查提交表的设计; 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)

);

【讨论】:

  • 关于主键的好点。但是一旦 submission.num 被定义为唯一的,correction 中的 user_idassignment_id 就只是多余的,应该完全删除,将 fk 减少到单独的 (num)
猜你喜欢
  • 2018-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多