Eu tenho uma tabela como a seguinte:
create table my_table (
id int8 not null,
id_A int8 not null,
id_B int8 not null,
id_C int8 null,
constraint pk_my_table primary key (id),
constraint u_constrainte unique (id_A, id_B, id_C)
);
E eu quero (id_A, id_B, id_C)
ser distinto em qualquer situação. Portanto, as duas inserções a seguir devem resultar em um erro:
INSERT INTO my_table VALUES (1, 1, 2, NULL);
INSERT INTO my_table VALUES (2, 1, 2, NULL);
Mas não se comporta como o esperado, porque, de acordo com a documentação, dois NULL
valores não são comparados entre si, portanto, ambas as inserções passam sem erros.
Como posso garantir a minha restrição exclusiva, mesmo que id_C
pode ser NULL
neste caso? Na verdade, a verdadeira questão é: posso garantir esse tipo de exclusividade no "sql puro" ou preciso implementá-lo em um nível superior (java no meu caso)?
postgresql
constraint
null
unique-constraint
Manuel Leduc
fonte
fonte
(1,2,1)
e(1,2,2)
nas(A,B,C)
colunas. Deve(1,2,NULL)
ser permitido adicionar ou não?Respostas:
Você pode fazer isso em SQL puro . Crie um índice exclusivo parcial, além do que você possui:
Dessa forma, você pode entrar
(a, b, c)
em sua tabela:Mas nada disso uma segunda vez.
Ou use dois
UNIQUE
índices parciais e nenhum índice completo (ou restrição). A melhor solução depende dos detalhes de seus requisitos. Comparar:Embora seja elegante e eficiente para uma única coluna anulável no
UNIQUE
índice, fica fora de controle rapidamente para mais. Discutindo isso - e como usar o UPSERT com índices parciais:Apartes
Não há uso para identificadores de maiúsculas e minúsculas sem aspas duplas no PostgreSQL.
Você pode considerar uma
serial
coluna como chave primária ou umaIDENTITY
coluna no Postgres 10 ou posterior. Relacionado:Assim:
Se você não espera mais de 2 bilhões de linhas (> 2147483647) durante a vida útil da sua tabela (incluindo desperdício e linhas excluídas), considere
integer
(4 bytes) em vez debigint
(8 bytes).fonte
Eu tive o mesmo problema e encontrei outra maneira de ter um NULL exclusivo na tabela.
No meu caso, o campo
foreign_key_field
é um número inteiro positivo e nunca será -1.Portanto, para responder ao Manual Leduc, outra solução pode ser
Presumo que os IDs não serão -1.
Qual é a vantagem em criar um índice parcial?
No caso em que você não tem a cláusula NOT NULL,
id_a
,id_b
eid_c
pode ser NULL juntos apenas uma vez.Com um índice parcial, os 3 campos podem ser NULL mais de uma vez.
fonte
COALESCE
pode ser eficaz para restringir as duplicatas, mas o índice não seria muito útil na consulta, pois é um índice de expressão que provavelmente não corresponderá às expressões de consulta. Ou seja, a menos queSELECT COALESCE(col, -1) ...
você não esteja atingindo o índice.Um Nulo pode significar que o valor não é conhecido para essa linha no momento, mas será adicionado, quando conhecido, no futuro (exemplo
FinishDate
para uma corridaProject
) ou que nenhum valor pode ser aplicado a essa linha (exemploEscapeVelocity
para um buraco negroStar
).Na minha opinião, geralmente é melhor normalizar as tabelas eliminando todos os Nulos.
No seu caso, você deseja permitir
NULLs
em sua coluna, mas deseja que apenas umNULL
seja permitido. Por quê? Que tipo de relacionamento é esse entre as duas tabelas?Talvez você possa simplesmente mudar a coluna para
NOT NULL
e armazenar, em vez deNULL
, um valor especial (como-1
) que se sabe que nunca aparece. Isso resolverá o problema de restrição de exclusividade (mas pode ter outros efeitos colaterais possivelmente indesejados. Por exemplo, usar o-1
significado "desconhecido / não se aplica" distorcerá qualquer soma ou cálculo médio da coluna. Ou todos esses cálculos terão de ser realizados em consideração o valor especial e ignorá-lo.)fonte