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

Composite PRIMARY KEY aplica restrições NOT NULL nas colunas envolvidas


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 &lt> -1)
 , CHECK (x_id &lt> -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.