Como restringir uma tabela de banco de dados para que apenas uma linha possa ter um valor específico em uma coluna?
-
05-07-2019 - |
Pergunta
Usando o Oracle, se um valor de coluna puder ser 'sim' ou 'não', é possível restringir uma tabela para que apenas uma linha possa ter um valor 'sim'?
Prefiro redesenhar a estrutura da tabela, mas isso não é possível.
Infelizmente, os valores nulos não são permitidos nesta tabela.
Solução
Use um índice baseado em função:
create unique index only_one_yes on mytable
(case when col='YES' then 'YES' end);
O Oracle apenas indexa as teclas que não são completamente nulas, e a expressão do caso aqui garante que todos os valores 'não' sejam alterados para nulos e, portanto, não indexados.
Outras dicas
Este é um hack de Kludgy, mas se a coluna permitir nulo, você poderá usar o NULL no lugar de "não" e usar "sim", assim como antes. Aplique uma restrição -chave única a essa coluna e você nunca receberá dois valores "sim", mas ainda terá muitos nos.
ATUALIZAÇÃO: @Nick PierPoint: sugeriu adicionar uma restrição de verificação para que os valores da coluna sejam restritos a apenas "sim" e nulo. A sintaxe é eliminada em sua resposta.
Você vai querer verificar um artigo de Tom Kyte com exatamente esta pergunta sendo feita e sua resposta:
http://tkyte.blogspot.com/2008/05/another-oty.html
Resumo: Não use gatilhos, não use transações autônomas, use duas tabelas.
Se você usar um banco de dados Oracle, deve saber Asktom e pegue seus livros.
Não funciona na definição da tabela.
No entanto, se você atualizar a tabela usando um gatilho chamando um procedimento armazenado, poderá garantir que apenas uma linha contenha "sim".
- Defina todas as linhas como "não"
- Defina a linha que você deseja sim
Seguindo do meu comentário para uma resposta anterior de Yukondude, eu adicionaria um índice exclusivo e uma restrição de cheque:
create table mytest (
yesorno varchar2(3 char)
);
create unique index uk_mytest_yesorno on mytest(yesorno);
alter table mytest add constraint ck_mytest_yesorno check (yesorno is null or yesorno = 'YES');
O Oracle apoia algo como índices filtrados (Na semana passada, ouvi dizer que, por exemplo, msql2008)? Talvez você possa definir um Chave única que se aplica apenas a linhas com o valor "Sim" em sua coluna.
Acho que usaria uma segunda tabela para apontar para a linha apropriada na sua tabela atual. Essa outra tabela também pode ser usada para armazenar valores de outras variáveis.