【问题标题】:PSQL enforce uniqueness, but within a subset of a table, not through the entire thingPSQL 强制唯一性,但在表的子集内,而不是通过整个事物
【发布时间】:2019-07-31 08:35:26
【问题描述】:

我正在使用 PostgreSQL 为课程创建一个评估数据库。

我希望评估名称在课程中是唯一的,但两门课程可以有相同名称的评估。

-- assessment contains the different assignments & labs that
-- students may submit their code to.
CREATE TABLE assessment (
    id           SERIAL PRIMARY KEY,
    name         VARCHAR(255)    UNIQUE NOT NULL,
    comments     TEXT            NOT NULL,
    type         ASSESSMENT_TYPE NOT NULL,
    course_id    SERIAL          NOT NULL,
    FOREIGN KEY (course_id) REFERENCES courses(id)
);

-- courses contains the information about a course. Since
-- the same course can run multiple times, a single course
-- is uniquely identified by (course_code, year, period)
CREATE TABLE courses (
    id          SERIAL PRIMARY KEY,
    name        VARCHAR(255) UNIQUE NOT NULL, -- Unique within all courses. Wrong!
    course_code VARCHAR(20)  NOT NULL,
    period      PERIOD       NOT NULL,
    year        INTEGER      NOT NULL
);

两个要点:

  1. 我可以在不更改架构的情况下执行此操作吗?

  2. 如果是这样,是否有更惯用的解决方案,可能包括架构更改?

【问题讨论】:

  • 如果课程由 (course_code, year, period) 唯一标识,那应该是唯一约束。
  • assessment.course_id 不应该是一个serial,而是一个普通的integer 列。
  • 这个不清楚。您是否在错误的表格中评论名称?你说你想要“评估名称”的某种独特性。课程名称是课程名称还是评估名称?评估中的名称是评估的名称还是课程的名称?课程名称值也是评估表名称值吗?评估表名称值也是课程名称值吗?请清楚地描述一行在表格中的含义以及对可能的数据库状态的限制是什么。 PS 是时候阅读有关信息建模和数据库设计的教科书了,包括对更高 NF 的规范化。
  • 您的“课程”表实际上是一个“提供”表 - 一个人注册并参加并评估课程的提供 - 应该由 course_code 建议而不是 PK/UNIQUE .您正在混淆地超载“课程”。 (您的设计可能会以一种不混淆的方式重载“名称”。但在您给出明确的表含义和约束之前,我们无法判断。)
  • 此外,当您在“评估名称在课程中是唯一的,但两门课程可以有相同名称的评估”中说“课程”时,不清楚您的意思是什么表,或者您的意思是否是唯一的课程 id 或 course_code 甚至一些 (assesment id, course) 对(适用于前两种“课程”含义中的任何一种)。

标签: postgresql database-design schema unique


【解决方案1】:

1。我可以在不更改架构的情况下执行此操作吗?

不,因为您这里有多个问题。

  1. 您的评估在名称上是全球唯一的,而不是在课程中。
  2. assessment.course_id 有自己的无用序列(SERIAL 只是 INTEGER + SEQUENCE
  3. courses定义了一个不存在的列数据类型:PERIOD(至少不超过11​​版)

2。如果是这样,是否有可能包括架构更改的更惯用的解决方案?

应该做你想做的修改的架构如下所示:

CREATE TABLE courses (
    id          SERIAL       PRIMARY KEY,
    name        VARCHAR(255) NOT NULL,
    course_code VARCHAR(20)  NOT NULL,
    period      tstzrange    NOT NULL
);

-- the following is required to build the proper unique constraint...
CREATE EXTENSION IF NOT EXISTS btree_gist;

-- the unique constraint: no two courses with same name at any point in time
ALTER TABLE courses
    ADD CONSTRAINT idx_unique_courses
    EXCLUDE USING GIST (name WITH =, period WITH &&);

CREATE TABLE assessment (
    id           SERIAL          PRIMARY KEY,
    name         VARCHAR(255)    NOT NULL,
    comments     TEXT            NOT NULL,
    type         ASSESSMENT_TYPE NOT NULL,
    course_id    INTEGER         NOT NULL REFERENCES courses(id),
    UNIQUE (course_id, name)
);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-20
    • 1970-01-01
    • 1970-01-01
    • 2011-02-18
    • 2014-07-18
    • 2010-09-26
    相关资源
    最近更新 更多