Cree un índice único:
CREATE UNIQUE INDEX matches_uni_idx ON matches
(greatest(winner, loser), least(winner, loser));
No puede ser un UNIQUE
o PRIMARY KEY
restricción, ya que solo funcionan con columnas, no con expresiones.
Puede agregar un serial
columna para servir como PK, pero con solo dos columnas de enteros, su PK original también es muy eficiente (ver comentarios). Y hace que ambas columnas NOT NULL
automáticamente. (De lo contrario, agregue NOT NULL
restricciones.)
También puede agregar un CHECK
restricción para descartar jugadores jugando contra ellos mismos:
CHECK (winner <> loser)
Sugerencia:para buscar un par de ID (donde no sabe quién ganó), cree las mismas expresiones en su consulta y se usará el índice:
SELECT * FROM matches
WHERE greatest(winner, loser) = 3 -- the greater value, obviously
AND least(winner, loser) = 1;
Si maneja parámetros desconocidos y no sabe cuál es mayor antes de tiempo:
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);
El contenedor CTE es solo por conveniencia para ingresar parámetros una sola vez y no es necesario en algunos contextos.