我的postgres数据库中有一个users表,其中role列使用了枚举.用户可以是CAPTAINPLAYER.

DROP TYPE IF EXISTS USER_ROLE CASCADE;
CREATE TYPE USER_ROLE AS ENUM ('CAPTAIN', 'PLAYER');

CREATE TABLE IF NOT EXISTS "user" {
  id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
  role USER_ROLE NOT NULL
);

我需要创建一个连接表,将many CAPTAIN个用户与many PLAYER个用户连接起来.

我可以创建一个这样的表:

CREATE TABLE IF NOT EXISTS user_user (
  user_captain_id INT,
  user_player_id INT,
  CONSTRAINT pk_user_user PRIMARY KEY (user_captain_id, user_player_id),
  CONSTRAINT fk_user_captain FOREIGN KEY (user_captain_id) REFERENCES "user"(id),
  CONSTRAINT fk_user_player FOREIGN KEY (user_player_id) REFERENCES "user"(id),
);

有没有办法添加约束,使user_captain_id必须是具有CAPTAIN角色的用户,而user_player_id必须是具有PLAYER角色的用户?

推荐答案

由于PostgreSQL不支持判断约束中的直接表引用,因此我结合使用了定制函数(check_user_role)和触发器来确保数据完整性.check_user_role函数判断给定的用户ID是否对应于指定的角色(CAPTAINPLAYER).然后,在USER_USER表上创建两个触发器(trigger_check_captain_roletrigger_check_player_role).这些触发器在任何INSERT或UPDATE操作之前调用该函数,以验证user_captain_id始终与CAPTAIN相关联,user_player_idPLAYER相关联.这种方法将确保连接表准确地反映用户及其各自角色之间的关系,维护数据库中角色关联的完整性和正确性.

CREATE OR REPLACE FUNCTION check_user_role(user_id INT, role USER_ROLE)
RETURNS BOOLEAN AS $$
DECLARE
  user_role USER_ROLE;
BEGIN
  SELECT role INTO user_role FROM "user" WHERE id = user_id;
  RETURN user_role = role;
END;
$$ LANGUAGE plpgsql;

然后写一个触发器

CREATE OR REPLACE FUNCTION trigger_check_captain_role()
RETURNS TRIGGER AS $$
BEGIN
  IF NOT check_user_role(NEW.user_captain_id, 'CAPTAIN') THEN
    RAISE EXCEPTION 'user_captain_id must have the CAPTAIN role';
  END IF;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trigger_user_user_before_insert_or_update_captain
BEFORE INSERT OR UPDATE ON user_user
FOR EACH ROW EXECUTE FUNCTION trigger_check_captain_role();

CREATE OR REPLACE FUNCTION trigger_check_player_role()
RETURNS TRIGGER AS $$
BEGIN
  IF NOT check_user_role(NEW.user_player_id, 'PLAYER') THEN
    RAISE EXCEPTION 'user_player_id must have the PLAYER role';
  END IF;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trigger_user_user_before_insert_or_update_player
BEFORE INSERT OR UPDATE ON user_user
FOR EACH ROW EXECUTE FUNCTION trigger_check_player_role();

Postgresql相关问答推荐

PostgreSQL数据文件是否仅在判断点期间写入磁盘?

如何在查询空字段时设置pgtype.comb为默认值?

在输入稍有错误的PostgreSQL表中进行快速字符串搜索

Postgresql我必须创建一个索引还是已经有一个索引了?

Haskell仆人发布FormUrlEncode for(向量字符串)字段

Select 所有数组类型和维度

如何 Select 任意行的相邻行(在 sql 或 postgresql 中)?

PostgreSQL - jsonb_each

如何使用 SpringBoot + JPA 存储 PostgreSQL jsonb?

SQLAlchemy 和多个进程的连接问题

丢弃顺序和级联

如何为查询执行设置语句超时

适配器 Ecto.Adapters.Postgres 未编译

如何在数据库表中查找重复条目?

在 PostgreSQL 数组中查找值的位置

Django 1.9.2 AssertionError:database connection isn't set to UTC

当成功有时会导致退出代码为 1 时,如何可靠地确定 pg_restore 是否成功?

Postgresql - 更新规则 - 可能有一个最后修改日期,自动更新该行的on update?

PG::ConnectionBad FATAL:role "Myname" does not exist

错误:prepared statement "S_1" already exists