Por exemplo, com uma tabela semelhante a esta:
create table foo(bar int identity, chk char(1) check (chk in('Y', 'N')));
Não importa se o sinalizador é implementado como a char(1)
, a bit
ou o que for. Eu só quero poder impor a restrição de que ele só pode ser definido em uma única linha.
constraint
database-agnostic
referential-integrity
Jack Douglas
fonte
fonte
Respostas:
SQL Server 2008 - índice exclusivo filtrado
fonte
SQL Server 2000, 2005:
Você pode aproveitar o fato de que apenas um nulo é permitido em um índice exclusivo:
para 2000, você pode precisar
SET ARITHABORT ON
(graças a @gbn por esta informação)fonte
Oráculo:
Como o Oracle não indexa entradas nas quais todas as colunas indexadas são nulas, você pode usar um índice exclusivo baseado em função:
Esse índice apenas indexará uma única linha no máximo.
Conhecendo esse fato do índice, você também pode implementar a coluna de bits de maneira um pouco diferente:
Aqui os valores possíveis para a coluna
chk
serãoY
eNULL
. Somente uma linha no máximo pode ter o valorY.
fonte
not null
restrição?not null
restrição se não quiser valores nulos (não ficou claro para mim a partir das especificações da pergunta). Somente uma linha pode ter o valor 'Y' em qualquer caso.default
)?Y
ou outranull
, veja minha atualização.null
s são ignorados - ao custo de alguma clareza, talvezEu acho que este é um caso de estruturar suas tabelas de banco de dados corretamente. Para torná-lo mais concreto, se você tem uma pessoa com vários endereços e deseja que seja o padrão, acho que você deve armazenar o ID do endereço do endereço padrão na tabela de pessoas, e não ter uma coluna padrão na tabela de endereços:
Você pode tornar o DefaultAddressID anulável, mas dessa maneira a estrutura impõe sua restrição.
fonte
MySQL:
As restrições de verificação são ignoradas no MySQL, portanto, temos que considerar
null
oufalse
como falsas etrue
verdadeiras. No máximo 1 linha pode terchk=true
Você pode considerar-se uma melhoria para adicionar um gatilho para a mudança
false
emtrue
em insert / update como uma solução para a ausência de uma restrição de verificação - IMO não é uma melhoria embora.Eu esperava poder usar um char (0) porque
Infelizmente, com o MyISAM e o InnoDB, pelo menos, recebo
--editar
afinal, essa não é uma boa solução, já que no MySQL
boolean
é sinônimotinyint(1)
e, portanto, permite valores não nulos que 0 ou 1. É possível quebit
seja uma escolha melhorfonte
null
,false
,true
- eu me pergunto se há algo mais puro ...Servidor SQL:
Como fazer isso:
A melhor maneira é um índice filtrado. Usa o DRI
SQL Server 2008 ou superior
Coluna computada com exclusividade. Usa DRI
Veja a resposta de Jack Douglas. SQL Server 2005 e anterior
Uma exibição indexada / materializada que é como um índice filtrado. Usa DRI
Todas as versões.
Desencadear. Usa código, não DRI.
Todas versões
Como não fazer:
Veja um dois três quatro
fonte
PostgreSQL:
--editar
ou (muito melhor), use um índice parcial exclusivo :
fonte
Esse tipo de problema é outro motivo pelo qual perguntei a esta pergunta:
Configurações de aplicativo no banco de dados
Se você tiver uma tabela de configuração de aplicativo em seu banco de dados, poderá ter uma entrada que faça referência ao ID do registro que você deseja que seja considerado 'especial'. Depois, basta pesquisar qual é o ID da sua tabela de configurações, dessa forma, você não precisa de uma coluna inteira para definir apenas um item.
fonte
Possíveis abordagens usando tecnologias amplamente implementadas:
1) Revogue privilégios de 'escritor' na mesa. Crie procedimentos CRUD que garantam que a restrição seja imposta nos limites da transação.
2) 6NF: solte a
CHAR(1)
coluna. Adicione uma tabela de referência restrita para garantir que sua cardinalidade não possa exceder uma:Altere a semântica do aplicativo para que o 'padrão' considerado seja a linha na nova tabela. Possivelmente use visualizações para encapsular essa lógica.
3) Solte a
CHAR(1)
coluna. Adicione umaseq
coluna inteira. Coloque uma restrição exclusivaseq
. Altere a semântica do aplicativo para que o "padrão" considerado seja a linha em que oseq
valor é um ou oseq
valor em maior / menor valor ou similar. Possivelmente use visualizações para encapsular essa lógica.fonte
Para quem usa o MySQL, aqui está um Procedimento Armazenado apropriado:
Para garantir que sua tabela esteja limpa e o procedimento armazenado esteja funcionando, supondo que o ID 200 seja o padrão, execute estas etapas:
Aqui está um gatilho que também ajuda:
Para garantir que sua tabela esteja limpa e o gatilho esteja funcionando, supondo que o ID 200 seja o padrão, execute estas etapas:
De uma chance !!!
fonte
No SQL Server 2000 e superior, você pode usar as Exibições indexadas para implementar restrições complexas (ou com várias tabelas) como a que você está solicitando.
Além disso, a Oracle possui uma implementação semelhante para visualizações materializadas com restrições de verificação diferida.
Veja meu post aqui .
fonte
Transição padrão SQL-92, amplamente implementada, por exemplo, SQL Server 2000 e superior:
Revogue privilégios de 'escritor' da tabela. Crie duas visualizações para
WHERE chk = 'Y'
eWHERE chk = 'N'
respectivamente, incluindoWITH CHECK OPTION
. Para aWHERE chk = 'Y'
visualização, inclua uma condição de pesquisa no sentido de que sua cardinalidade não pode exceder uma. Conceda privilégios de 'escritor' nas visualizações.Código de exemplo para as visualizações:
fonte
Aqui está uma solução para MySQL e MariaDB usando colunas virtuais um pouco mais elegantes. Requer MySQL> = 5.7.6 ou MariaDB> = 5.2:
Crie uma coluna virtual que é NULL se você não deseja aplicar a restrição exclusiva:
(Para MySQL, use em
STORED
vez dePERSISTENT
.)fonte
Padrão SQL COMPLETO-92: use uma subconsulta em uma
CHECK
restrição, não amplamente implementada, por exemplo, suportada no Access2000 (ACE2007, Jet 4.0, qualquer que seja) e acima quando estiver no modo de consulta ANSI-92 .Código de exemplo: as
CHECK
restrições de nota no Access são sempre no nível da tabela. Como aCREATE TABLE
declaração na pergunta usa umaCHECK
restrição no nível da linha , ela precisa ser ligeiramente alterada adicionando uma vírgula:fonte
Eu só dei uma olhada nas respostas, então poderia ter perdido uma resposta semelhante. A idéia é usar uma coluna gerada que seja o pk ou uma constante que não exista como um valor para o pk
AFAIK, isso é válido no SQL2003 (desde que você esteja procurando uma solução independente). O DB2 permite, sem ter certeza de quantos outros fornecedores o aceitam.
fonte