PostgreSQL如何限制列值只能为同一行其他两列的取值之一
PostgreSQL 实现对战表获胜方字段取值限制的方案
要实现winner_player只能取同记录内player_1或player_2的取值限制,最简洁高效的方式是给表添加CHECK行级约束,这是PostgreSQL原生提供的行数据校验能力,校验逻辑直白、执行性能高,不需要额外编写触发器函数。
给已存在的match表添加约束
如果你的match表已经建好,直接执行以下DDL语句即可:
-- 不允许winner_player为空的场景(对战记录必须有确定结果) ALTER TABLE match ADD CONSTRAINT check_match_winner_valid CHECK (winner_player = player_1 OR winner_player = player_2);
如果业务中允许未结束的对战记录暂时把winner_player设为空值,使用兼容空值的约束逻辑:
-- 允许winner_player为空的场景(支持存储未决出胜负的对战记录) ALTER TABLE match ADD CONSTRAINT check_match_winner_valid CHECK (winner_player IS NULL OR winner_player = player_1 OR winner_player = player_2);
建表时直接内置约束
如果还没创建match表,可以直接把校验逻辑写在建表语句里,从建表阶段就拦截非法数据:
CREATE TABLE match ( match_id BIGINT PRIMARY KEY, player_1 BIGINT NOT NULL REFERENCES player(player_id), player_2 BIGINT NOT NULL REFERENCES player(player_id), winner_player BIGINT REFERENCES player(player_id), -- 获胜方取值校验约束 CONSTRAINT check_match_winner_valid CHECK ( winner_player IS NULL OR winner_player = player_1 OR winner_player = player_2 ) );
约束生效效果
约束添加完成后,任何插入、更新操作只要出现winner_player取值既不等于player_1也不等于player_2的情况,数据库会直接抛出校验失败错误,阻止非法数据写入,报错示例如下:
ERROR: new row for relation "match" violates check constraint "check_match_winner_valid"
DETAIL: Failing row contains (1, 1001, 1002, 1003).
这类同表字段间的固定规则校验,优先用CHECK约束实现即可,相比触发器方案,它没有额外的函数调用开销,约束逻辑直接和表定义绑定,后续维护排查也更方便。
内容的提问来源于stack exchange,提问作者Shahid Ali
相关产品推荐
相关产品推荐

