Se você precisar para permitir valores NULL, use um
UNIQUE
restrição em vez de uma PRIMARY KEY
(e adicione uma coluna PK substituta, sugiro um serial
). Isso permite que as colunas sejam NULL:Distribuidor
CREATE TABLE distributor (
distributor_id serial PRIMARY KEY
, m_id integer
, x_id integer
, UNIQUE(m_id, x_id)
);
Observação , no entanto (por documentação):
Para fins de restrição exclusiva, os valores nulos não são considerados iguais.
No seu caso, você pode digitar algo como
(1, NULL)
para (m_id, x_id)
qualquer número de vezes sem violar a restrição. Postgres nunca considera dois valores NULL iguais - conforme definição no padrão SQL. Se você precisar tratar
NULL
valores iguais para não permitir tais "duplicatas", vejo duas opções :1. Dois índices parciais
Além disso para o
UNIQUE
restrição acima:CREATE UNIQUE INDEX dist_m_uni_idx ON distributor (m_id) WHERE x_id IS NULL;
CREATE UNIQUE INDEX dist_x_uni_idx ON distributor (x_id) WHERE m_id IS NULL;
Mas isso fica fora de controle rapidamente com mais de duas colunas que podem ser NULL. Ver:
- Criar restrição exclusiva com colunas nulas
2. Um UNIQUE
com várias colunas índice em expressões
Em vez da restrição UNIQUE. Precisamos de um valor padrão gratuito que nunca esteja presente nas colunas envolvidas, como
-1
. Adicionar CHECK
restrições para não permitir:CREATE TABLE distributor (
distributor serial PRIMARY KEY
, m_id integer
, x_id integer
, CHECK (m_id <> -1)
, CHECK (x_id <> -1)
);
CREATE UNIQUE INDEX distributor_uni_idx ON distributor (COALESCE(m_id, -1)
, COALESCE(x_id, -1))
Como certos RDBMS lidam com as coisas nem sempre é um indicador útil para o comportamento adequado. O manual do Postgres sugere isso:
Isso significa que mesmo na presença de uma restrição exclusiva é possível armazenar linhas duplicadas que contenham um valor nulo em pelo menos uma das colunas restritas. Esse comportamento está em conformidade com o padrão SQL, mas ouvimos que outros bancos de dados SQL podem não seguir essa regra . Portanto, tenha cuidado ao desenvolver aplicativos destinados a serem portáteis.
Minha ênfase em negrito.