Create a unique index:
CREATE UNIQUE INDEX matches_uni_idx ON matches
(greatest(winner, loser), least(winner, loser));
Can't be a UNIQUE
or PRIMARY KEY
constraint, since those only work with columns, not expressions.
You might add a serial
column to serve as PK, but with just two integer columns, your original PK is very efficient, too (see comments). And it makes both columns NOT NULL
automatically. (Else, add NOT NULL
constraints.)
You also might add a CHECK
constraint to rule out players playing against themselves:
CHECK (winner <> loser)
Hint: To search for a pair of IDs (where you don't know who won), build the same expressions into your query, and the index will be used:
SELECT * FROM matches
WHERE greatest(winner, loser) = 3 -- the greater value, obviously
AND least(winner, loser) = 1;
If you deal with unknown parameters and you don't know which is greater ahead of time:
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);
The CTE wrapper is just for convenience to enter parameters once only and not necessary in some contexts.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…