A restrição CHECK no MySQL não está funcionando

126

Primeiro eu criei uma tabela como

CREATE TABLE Customer (
  SD integer CHECK (SD > 0),
  Last_Name varchar (30),
  First_Name varchar(30)
);

e depois inseri valores nessa tabela

INSERT INTO Customer values ('-2','abc','zz');

O MySQL não mostra um erro, ele aceitou os valores.

JohnRaja
fonte
Concordo parcialmente. Como você tentou usá-lo, pode-se supor que você estava fazendo as duas perguntas. De fato, a resposta que você aceitou está explicando principalmente por que ela não funciona.
igorrs
1
Você pode votar nesta solicitação de recurso: bugs.mysql.com/bug.php?id=3464, mas ela não recebe atenção há uma década.
Jared Beck
11
Você pode usar as restrições CHECK no MariaDB da versão 10.2.1 .
joanq

Respostas:

140

O MySQL 8.0.16 é a primeira versão que suporta restrições CHECK.

Leia https://dev.mysql.com/doc/refman/8.0/en/create-table-check-constraints.html

Se você usa o MySQL 8.0.15 ou anterior, o Manual de Referência do MySQL diz:

A CHECKcláusula é analisada, mas ignorada por todos os mecanismos de armazenamento.

Tente um gatilho ...

mysql> delimiter //
mysql> CREATE TRIGGER trig_sd_check BEFORE INSERT ON Customer 
    -> FOR EACH ROW 
    -> BEGIN 
    -> IF NEW.SD<0 THEN 
    -> SET NEW.SD=0; 
    -> END IF; 
    -> END
    -> //
mysql> delimiter ;

Espero que ajude.

David Kerins
fonte
9
Aqui você vai encontrar como provocar um erro em vez disso: stackoverflow.com/a/7189396/1144966
petermeissner
41
Este é um dos vastos e brilhantes arco-íris de razões pelas quais eu sempre usarei o PostgreSQL em vez do MySQL, se houver uma escolha.
Reinderien 11/11
5
Gostaria de saber se seriam 10 ou 15 minutos de desenvolvimento no MySQL para lançar um aviso se o analisador encontrar uma CHECKrestrição definida. Ahhh, isso seria muito simples ...
gaborsch
75

Infelizmente, o MySQL não suporta restrições de verificação SQL. Você pode defini-los na sua consulta DDL por motivos de compatibilidade, mas eles são ignorados.

Existe uma alternativa simples

Você pode criar BEFORE INSERTe BEFORE UPDATEdisparar que causa um erro ou define o campo com seu valor padrão quando os requisitos dos dados não são atendidos.

Exemplo para BEFORE INSERTtrabalhar após o MySQL 5.5

DELIMITER $$
CREATE TRIGGER `test_before_insert` BEFORE INSERT ON `Test`
FOR EACH ROW
BEGIN
    IF CHAR_LENGTH( NEW.ID ) < 4 THEN
        SIGNAL SQLSTATE '12345'
            SET MESSAGE_TEXT := 'check constraint on Test.ID failed';
    END IF;
END$$   
DELIMITER ;  

Antes do MySQL 5.5, você tinha que causar um erro, por exemplo, chamar um procedimento indefinido.

Nos dois casos, isso causa uma reversão implícita da transação. O MySQL não permite a própria instrução ROLLBACK dentro de procedimentos e gatilhos.

Se você não deseja reverter a transação (INSERT / UPDATE deve passar mesmo com uma falha de "restrição de verificação", você pode sobrescrever o valor usando o SET NEW.ID = NULLque definirá o ID para o valor padrão dos campos, não faz muito sentido para um ID tho

Edit: Removida a citação perdida.

Em relação ao :=operador:

Ao contrário =, o :=operador nunca é interpretado como um operador de comparação. Isso significa que você pode usar :=em qualquer instrução SQL válida (não apenas nas instruções SET) para atribuir um valor a uma variável.

https://dev.mysql.com/doc/refman/5.6/en/assignment-operators.html

Sobre citações de identificador de backtick:

O caractere de citação do identificador é o backtick ("` ")

Se o modo SQL ANSI_QUOTES estiver ativado, também será permitido citar identificadores entre aspas duplas

http://dev.mysql.com/doc/refman/5.6/en/identifiers.html

Michel Feldheim
fonte
7
... não é muito simples, pelo menos em comparação com o CHECK :(. Coupla tutes : net.tutsplus.com/tutorials/databases/… , sitepoint.com/how-to-create-mysql-triggers
Ben
ugh isso parece muito volumoso. Eu acho que prefiro criar uma tupla em python e verificar os valores lá em vez de colocar isso.
OzzyTheGiant
Pergunta rápida: por que isso não funciona sem definir o DELIMITER?
ddz 4/17/17
52

CHECK restrições são ignoradas pelo MySQL, conforme explicado em um minúsculo comentário nos documentos: CREATE TABLE

A CHECKcláusula é analisada, mas ignorada por todos os mecanismos de armazenamento.

ypercubeᵀᴹ
fonte
2
@thefiloe: correto, em outro DBMS com implementação correta de CHECKrestrições, se a CHECKavaliação até FALSEentão a inserção (ou atualização) não for feita e um erro for causado.
usar o seguinte comando
Corrigido no MariaDB (consulte esta resposta stackoverflow.com/a/44333349 ).
Jérôme
@ Jérôme Eu sei, tenho algumas respostas (mais recentes) que incluem melhorias nessa área (houve outras maneiras de solucionar esse problema, tanto no MariaDB quanto no MySQL, antes que o MariaDB implementasse adequadamente as restrições CHECK). O que não tenho certeza é se devo editar todas as minhas respostas antigas!
precisa saber é o seguinte
Suponho que meu comentário com um link para uma resposta mais recente seja bom. Ou melhor que nada. Talvez eu devesse ter editado. Não pretendia pressionar você a fazer nada.
Jérôme
1

As restrições de verificação são suportadas a partir da versão 8.0.15 (ainda a ser lançada)

https://bugs.mysql.com/bug.php?id=3464

[23 de janeiro de 16:24] Paul Dubois

Publicado pelo desenvolvedor: Corrigido em 8.0.15.

Anteriormente, o MySQL permitia uma forma limitada de sintaxe de restrição CHECK, mas a analisava e a ignorava. O MySQL agora implementa os principais recursos das restrições CHECK de tabela e coluna, para todos os mecanismos de armazenamento. As restrições são definidas usando as instruções CREATE TABLE e ALTER TABLE.

James
fonte
1

Atualize para o MySQL 8.0.16 para usar checks:

A partir do MySQL 8.0.16, CREATE TABLE permite os principais recursos das restrições CHECK da tabela e da coluna, para todos os mecanismos de armazenamento. CREATE TABLE permite a seguinte sintaxe de restrição CHECK, para restrições de tabela e restrições de coluna

Documentação de verificações do MySQL

sdlins
fonte
-2

tente com set sql_mode = 'STRICT_TRANS_TABLES'OUSET sql_mode='STRICT_ALL_TABLES'

Kanagu
fonte
2
que actuall não ajuda (MySQL 5.6) impede a entrada de dados de falsa tipo, mas não de entrada de dados que não atendem a CHECKrestrição
petermeissner