Erstellen Sie einen eindeutigen Index:
CREATE UNIQUE INDEX matches_uni_idx ON matches
(greatest(winner, loser), least(winner, loser));
Darf kein UNIQUE
sein oder PRIMARY KEY
Einschränkung, da diese nur mit Spalten arbeiten, nicht mit Ausdrücken.
Sie können eine serial
hinzufügen Spalte als PK dienen, aber mit nur zwei Integer-Spalten ist Ihre ursprüngliche PK auch sehr effizient (siehe Kommentare). Und es macht beide Spalten zu NOT NULL
automatisch. (Andernfalls fügen Sie NOT NULL
hinzu Beschränkungen.)
Sie können auch ein CHECK
hinzufügen Einschränkung, um Spieler auszuschließen, die gegen sich selbst spielen:
CHECK (winner <> loser)
Tipp:Um nach einem ID-Paar zu suchen (wobei Sie nicht wissen, wer gewonnen hat), bauen Sie dieselben Ausdrücke in Ihre Abfrage ein, und der Index wird verwendet:
SELECT * FROM matches
WHERE greatest(winner, loser) = 3 -- the greater value, obviously
AND least(winner, loser) = 1;
Wenn Sie es mit unbekannten Parametern zu tun haben und im Voraus nicht wissen, welcher der größere ist:
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);
Der CTE-Wrapper dient nur der Bequemlichkeit, um Parameter nur einmal einzugeben, und ist in manchen Zusammenhängen nicht erforderlich.