PSQL обеспечивает уникальность, но в пределах подмножества таблицы, а не через все это - PullRequest
0 голосов
/ 09 марта 2019

Я создаю базу данных оценок для курсов с использованием 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. Если так, есть ли более идиоматическое решение, которое может включать изменения схемы?

1 Ответ

0 голосов
/ 10 марта 2019

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