Bab*_*k K 6 sql postgresql ddl database-design unique-constraint
我在 Postgres 数据库中有两个名为players& 的表matches,如下所示:
CREATE TABLE players (
    name text NOT NULL,
    id serial PRIMARY KEY
);
CREATE TABLE matches (
    winner int REFERENCES players (id),
    loser int REFERENCES players (id),
    -- to prevent rematch btw players
    CONSTRAINT unique_matches
    PRIMARY KEY (winner, loser)
);
如何确保仅将(winner, loser)或的唯一组合(loser, winner)用于matches主键,以便matches表不允许插入:
INSERT INTO matches VALUES (2, 1);
如果它已经有一行包含VALUES (1, 2)像:
 winner | loser
--------+-------
      1 |     2
目标是避免相同玩家之间的比赛进入。
创建唯一索引:
CREATE UNIQUE INDEX matches_uni_idx ON matches
   (greatest(winner, loser), least(winner, loser));
不能是 aUNIQUE或PRIMARY KEYconstraint,因为那些只适用于列,而不适用于表达式。
您可以添加一serial列作为 PK,但只有两个整数列,您的原始 PK 也非常有效(请参阅评论)。它会NOT NULL自动生成两列。(否则,添加NOT NULL约束。)
您还可以添加一个CHECK约束来排除玩家与自己对战:
CHECK (winner <> loser)
提示:要搜索一对 ID(您不知道谁赢了),请在查询中构建相同的表达式,并将使用索引:
SELECT * FROM matches
WHERE  greatest(winner, loser) = 3  -- the greater value, obviously
AND    least(winner, loser) = 1;
如果您处理未知参数并且您不知道哪个参数更大:
WITH input AS (SELECT $id1 AS _id1, $id2 AS _id2)  -- input once
SELECT * FROM matches, input
WHERE  greatest(winner, loser) = greatest(_id1, _id2)
AND    least(winner, loser) = least(_id1, _id2);
CTE 包装器只是为了方便只输入一次参数,在某些情况下不需要。
| 归档时间: | 
 | 
| 查看次数: | 1345 次 | 
| 最近记录: |