Tenho a seguinte tabela.
create table test (
id smallint unsigned AUTO_INCREMENT,
age tinyint not null,
primary key(id),
check (age<20)
);
O problema é que a CHECK
restrição não funciona na coluna de idade. Por exemplo, quando insiro 222 para o campo de idade o MySQL o aceita.
As restrições CHECK não são implementadas no MySQL. De CRIAR TABELA
Também tem sido um bug relatado por quase 8 anos ...
O que você precisa são dois gatilhos para detectar a condição de idade inválida
O seguinte é baseado em um método de interceptação de erros improvisado para MySQL Triggers do Capítulo 11, Páginas 254-256 do livro MySQL Stored Procedure Programming sob o subtítulo 'Validating Data with Triggers' :
Aqui está o resultado:
Observe também que os valores de incremento automático não são desperdiçados ou perdidos.
De uma chance !!!
Além da boa solução de gatilho do @Rolando, há outra solução alternativa para esse problema no MySQL (até
CHECK
que as restrições sejam implementadas).Como emular algumas
CHECK
restrições no MySQLPortanto, se você preferir restrições de integridade referencial e quiser evitar gatilhos (por causa dos problemas no MySQL quando você tem ambos em suas tabelas), você pode usar outra pequena tabela de referência:
Preencha-o com 20 linhas:
Então sua tabela ficaria:
Você terá que remover o acesso de gravação à
age_allowed
tabela, para evitar a adição ou remoção acidental de linhas.Este truque não funcionará com
FLOAT
colunas de tipo de dados, infelizmente (muitos valores entre0.0
e20.0
).Como emular
CHECK
restrições arbitrárias no MySQL (5.7) e MariaDB (de 5.2 a 10.1)Como o MariaDB adicionou colunas computadas em sua versão 5.2 (versão GA: 2010-11-10 ) e MySQL em 5.7 (versão GA: 2015-10-21 ) - que eles chamam
VIRTUAL
eGENERATED
respectivamente - que podem ser persistidas, ou seja, armazenadas no table - eles os chamamPERSISTENT
eSTORED
respectivamente - podemos usá-los para simplificar a solução acima e, melhor ainda, estendê-la para emular/imporCHECK
restrições arbitrárias ):Como acima, precisaremos de uma tabela de ajuda, mas com uma única linha desta vez que atuará como uma tabela "âncora". Melhor ainda, esta tabela pode ser usada para qualquer número de
CHECK
restrições.Em seguida, adicionamos uma coluna computada que avalia como
TRUE
/FALSE
/UNKNOWN
, exatamente comoCHECK
faria uma restrição - mas essa coluna tem umaFOREIGN KEY
restrição para nossa tabela âncora. Se a condição/coluna for avaliadaFALSE
para algumas linhas, as linhas serão rejeitadas devido ao FK.Se a condição/coluna for avaliada como
TRUE
ouUNKNOWN
(NULL
), as linhas não serão rejeitadas, exatamente como deveria acontecer comCHECK
as restrições:O exemplo é para a versão MySQL 5.7. No MariaDB (versões 5.2+ até 10.1), só precisamos modificar a sintaxe e declarar a coluna como
PERSISTENT
em vez deSTORED
. Na versão 10.2 a palavra-STORED
chave também foi adicionada, então o exemplo acima funciona nos dois tipos (MySQL e MariaDB) para as versões mais recentes.Se quisermos impor muitas
CHECK
restrições (o que é comum em muitos projetos), basta adicionar uma coluna computada e uma chave estrangeira para cada uma delas. Precisamos apenas de umatruth
tabela no banco de dados. Ele deve ter uma linha inserida e, em seguida, todos os acessos de gravação removidos.No MariaDB mais recente, no entanto, não precisamos mais realizar todas essas acrobacias, pois as
CHECK
restrições foram implementadas na versão 10.2.1 (versão alfa: 2016-Jul-04)!A versão 10.2.2 atual ainda é uma versão beta, mas parece que o recurso estará disponível na primeira versão estável da série MariaDB 10.2.
Como expliquei neste artigo , a partir da versão 8.0.16, o MySQL adicionou suporte para restrições CHECK personalizadas:
Anteriormente, isso só estava disponível usando os gatilhos BEFORE INSERT e BEFORE UPDATE:
Para obter mais detalhes sobre como emular restrições CHECK usando gatilhos de banco de dados para versões do MySQL anteriores à 8.0.16, confira este artigo .