如何要求表A的行具有唯一的(k1,k2)并且k2是k3引用的行的外键? k1、k2 和 k3 是 A 中的外键

问题描述 投票:0回答:1

我在问题标题中提出的问题思考起来有点复杂,所以这是我实际的具体问题:

我有四个相关表:课程组、课程、用户和选择。以下规则适用:

  • 用户可以选择课程,我的服务器会自动将它们添加到选择表中。
  • 用户在每个课程组中最多有一个选择;也就是说,“(课程组,用户)”对唯一标识一门课程(如果有)。
  • 每门课程都与一个且仅一个课程组相关联。

我尝试使用以下模式:

-- Many irrelevant fields have been redacted

CREATE TABLE cgroups (name TEXT PRIMARY KEY NOT NULL);

CREATE TABLE courses (
    id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    cgroup TEXT NOT NULL,
    FOREIGN KEY(cgroup) REFERENCES cgroups(name)
);

CREATE TABLE users (id TEXT PRIMARY KEY NOT NULL);

CREATE TABLE choices (
    PRIMARY KEY (userid, courseid), -- Primary key guarantees unique

    userid TEXT NOT NULL,
    FOREIGN KEY(userid) REFERENCES users(id),

    courseid INTEGER NOT NULL,
    FOREIGN KEY(courseid) REFERENCES courses(id),

    -- Which course group does this choice belong to? Primary problem here:
    -- I want to guarantee that the cgroup here corresponds to the cgroup
    -- of the course referenced above.
    cgroup TEXT NOT NULL,
    FOREIGN KEY(cgroup) REFERENCES cgroups(name),

    -- Attempt to ensure that each user can only choose one course from a cgroup
    UNIQUE (userid, cgroup)
);

这里的问题是

choice.cgroup
不限于对应于
courses[choice.courseid].cgroup
。我该如何表达这个约束呢?或者是否有其他方法可以根据我上面提出的规则设计模式?

postgresql
1个回答
0
投票

以下脚本创建的 schema 确保每一门课程都与一个课程组关联,用户只能选择一次课程,每个组中只能选择一门课程,并且选择的课程和组与课程一致课程定义:

CREATE TABLE cgroups (
  id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  name TEXT NOT NULL,
  UNIQUE (name)
);

CREATE TABLE courses (
  id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  cgroup_id INTEGER NOT NULL REFERENCES cgroups (id),
  name TEXT NOT NULL,
  UNIQUE (name),
  UNIQUE (id, cgroup_id)
);

CREATE TABLE users (
  id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  name TEXT NOT NULL,
  UNIQUE (name)
);

CREATE TABLE choices (
  user_id INTEGER NOT NULL REFERENCES users (id),
  course_id INTEGER NOT NULL,
  cgroup_id INTEGER NOT NULL,
  PRIMARY KEY (user_id, course_id), -- Primary key guarantees unique
  -- referencing (course_id, cgroup_id) ensures that the pair are consistent with the course
  FOREIGN key (course_id, cgroup_id) REFERENCES courses (id, cgroup_id),
  -- ensure that each user can only choose one course per cgroup
  -- column order facilitates efficient searches for users with courses in a specific cgroup
  UNIQUE (cgroup_id, user_id)
);

已将合成主键

id
添加到每个表(
choices
除外),以便更轻松地更新名称,而无需更新对该名称的每个引用。索引和搜索整数列通常比文本列更有效。由于
choices
本质上是一个 associativebridge 表,因此不需要合成密钥。

这种模式的一个问题是改变课程和团体关联变得很困难。限制用户从组中选择单个课程似乎更像是一个业务问题,而不是数据完整性问题。一般来说,数据库模型应该强制数据完整性并将业务逻辑留给应用程序。

© www.soinside.com 2019 - 2024. All rights reserved.