Sql 如何创建具有唯一组合主键的Postgres表?
我在Postgres DB中有两个名为Sql 如何创建具有唯一组合主键的Postgres表?,sql,postgresql,database-design,ddl,unique-constraint,Sql,Postgresql,Database Design,Ddl,Unique Constraint,我在Postgres DB中有两个名为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 bt
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)
);
如何确保只有(赢家,输家)
或(输家,输家)
的唯一组合用于匹配
主键,以便匹配
表不允许插入:
INSERT INTO matches VALUES (2, 1);
如果它已经有一行包含值(1,2)
如:
winner | loser
--------+-------
1 | 2
目标是避免同一球员之间的比赛进入。Postgres不支持表达式上的限制,因此我无法将直接的方式将此要求表示为约束。不过,您可以做的一件事是更改表的结构,使其包含比赛中球员的两列(主键),该约束确保player1始终具有两列中较小的id,并添加一列以指示胜利者:
CREATE TABLE matches (
p1 int REFERENCES players (id),
p2 int REFERENCES players (id),
p1winner boolean,
CONSTRAINT matches_pk PRIMARY KEY (p1, p2),
CONSTRAINT matches_players_order CHECK (p1 < p2)
);
创建表匹配(
p1 int参考球员(id),
p2 int参考球员(id),
p1是一个布尔值,
约束匹配主键(p1,p2),
约束匹配\u玩家\u顺序检查(p1
创建唯一索引:
CREATE UNIQUE INDEX matches_uni_idx ON matches
(greatest(winner, loser), least(winner, loser));
不能是,因为这些只能处理列,不能处理表达式
您可以添加一个serial
列作为主键,但是只有两个整数列,您的原始主键也非常有效(请参见注释)。并且它会自动使两列都不为NULL
。(否则,添加notnull
约束。)
您还可以添加检查
约束,以排除与自己对抗的玩家:
CHECK (winner <> loser)
如果您处理未知参数,但不知道哪一个参数更大:
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包装只是为了方便,只需输入一次参数,在某些情况下不需要。谢谢@Erwin。它就像一个符咒;)但是,您是否有理由建议使用一个
serial
列作为PK,而不是我以前使用的方式(PRIMARY KEY(赢家,输家)
)?再次感谢:)@BabakK:您是对的,PRIMARY KEY(赢家,输家)
将以这种方式工作。对于两个整数列,它也非常高效。如果对表有FK引用,则使用单列代理PK可能更简单。
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);