PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Como criar uma tabela Postgres com chave primária combinada exclusiva?


Crie um índice exclusivo:
CREATE UNIQUE INDEX matches_uni_idx ON matches
   (greatest(winner, loser), least(winner, loser));

Não pode ser um UNIQUE ou PRIMARY KEY restrição, já que eles só funcionam com colunas, não com expressões.

Você pode adicionar um serial column para servir como PK, mas com apenas duas colunas inteiras, seu PK original também é muito eficiente (veja comentários). E torna ambas as colunas NOT NULL automaticamente. (Caso contrário, adicione NOT NULL restrições.)

Você também pode adicionar um CHECK restrição para descartar jogadores jogando contra eles mesmos:
CHECK (winner <> loser)

Dica:para pesquisar um par de IDs (onde você não sabe quem ganhou), construa as mesmas expressões em sua consulta e o índice será usado:
SELECT * FROM matches
WHERE  greatest(winner, loser) = 3  -- the greater value, obviously
AND    least(winner, loser) = 1;

Se você lida com parâmetros desconhecidos e não sabe qual é maior antecipadamente:
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);

O wrapper CTE é apenas por conveniência para inserir parâmetros apenas uma vez e não é necessário em alguns contextos.