Il vincolo CHECK in MySQL non funziona


126

Per prima cosa ho creato una tabella come

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

e quindi inserito i valori in quella tabella

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

MySQL non mostra un errore, ha accettato i valori.


Parzialmente d'accordo. Dato che hai provato a usarlo, si può presumere che stavi facendo entrambe le domande. In effetti, la risposta che hai accettato spiega principalmente perché non funziona.
Igororr

1
Puoi votare questa richiesta di funzionalità: bugs.mysql.com/bug.php?id=3464 ma non ha ricevuto alcuna attenzione da un decennio.
Jared Beck,

11
È possibile utilizzare i vincoli CHECK in MariaDB dalla versione 10.2.1 .
joanq,

Risposte:


140

MySQL 8.0.16 è la prima versione che supporta i vincoli CHECK.

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

Se usi MySQL 8.0.15 o precedenti, il Manuale di riferimento di MySQL dice:

La CHECKclausola viene analizzata ma ignorata da tutti i motori di archiviazione.

Prova un grilletto ...

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 ;

Spero che aiuti.


9
Qui troverete come attivare un errore invece: stackoverflow.com/a/7189396/1144966
petermeissner

41
Questo è tra il vasto arcobaleno scintillante di motivi per cui userò sempre PostgreSQL invece di MySQL, a scelta.
Reinderien,

5
Mi chiedo se sarebbe uno sviluppo di 10 minuti o 15 minuti in MySQL emettere un avviso se il parser incontra un CHECKvincolo definito. Ahhh, sarebbe troppo semplice ...
Gaborsch,

75

Purtroppo MySQL non supporta i vincoli di controllo SQL. È possibile definirli nella query DDL per motivi di compatibilità, ma vengono semplicemente ignorati.

C'è una semplice alternativa

È possibile creare BEFORE INSERTe BEFORE UPDATEtrigger che causano un errore o impostano il campo sul valore predefinito quando i requisiti dei dati non sono soddisfatti.

Esempio per BEFORE INSERTlavorare dopo 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 ;  

Prima di MySQL 5.5 dovevi causare un errore, ad esempio chiamare una procedura non definita.

In entrambi i casi ciò provoca un rollback implicito della transazione. MySQL non consente l'istruzione ROLLBACK stessa all'interno di procedure e trigger.

Se non si desidera eseguire il rollback della transazione (INSERT / UPDATE dovrebbe passare anche con un "vincolo di controllo" non riuscito, è possibile sovrascrivere il valore utilizzando il SET NEW.ID = NULLquale imposterà l'id sul valore predefinito dei campi, non ha davvero senso per un id Però

Modifica: rimossa la citazione vagante.

Per quanto riguarda l' :=operatore:

Diversamente =, l' :=operatore non viene mai interpretato come un operatore di confronto. Ciò significa che è possibile utilizzare :=in qualsiasi istruzione SQL valida (non solo nelle istruzioni SET) per assegnare un valore a una variabile.

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

Per quanto riguarda le citazioni dell'identificatore backtick:

Il carattere di citazione dell'identificatore è il backtick ("` ")

Se la modalità SQL ANSI_QUOTES è abilitata, è anche possibile citare gli identificativi tra virgolette doppie

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



ma questo sembra molto voluminoso. Penso che preferisco creare una tupla in pitone e controllare i valori lì invece di
inserirla

Domanda veloce: perché questo non funziona senza l'impostazione DELIMITER?
ddz,

52

CHECK i vincoli sono ignorati da MySQL come spiegato in un minuscolo commento nei documenti: CREATE TABLE

La CHECKclausola viene analizzata ma ignorata da tutti i motori di archiviazione.


2
@thefiloe: Corretto, in altri DBMS con la corretta implementazione dei CHECKvincoli, se la CHECKvalutazione procede quindi all'inserimento FALSE(o all'aggiornamento) e non si verifica un errore.
ypercubeᵀᴹ

Risolto in MariaDB (vedi questa risposta stackoverflow.com/a/44333349 ).
Jérôme,

@Jérôme Lo so, ho alcune (più recenti) risposte che includono miglioramenti in quest'area (c'erano stati altri modi per risolvere questo problema, sia in MariaDB che MySQL, prima che MariaDB implementasse correttamente i vincoli CHECK). Quello che non sono sicuro è se dovessi andare a modificare tutte le mie vecchie risposte!
ypercubeᵀᴹ

Suppongo che il mio commento con un link a una risposta più recente vada bene. O meglio di niente. Forse avrei dovuto modificarlo. Non intendevo farti pressione per fare qualcosa.
Jérôme,



1

Controllare i vincoli sono supportati dalla versione 8.0.15 (ancora da rilasciare)

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

[23 gennaio 16:24] Paul Dubois

Inserito dallo sviluppatore: risolto in 8.0.15.

In precedenza, MySQL consentiva una forma limitata di sintassi del vincolo CHECK, ma la analizzava e la ignorava. MySQL ora implementa le funzionalità principali dei vincoli CHECK di tabella e colonna, per tutti i motori di archiviazione. I vincoli sono definiti usando le istruzioni CREATE TABLE e ALTER TABLE.


1

Aggiornamento a MySQL 8.0.16 per utilizzare checks:

A partire da MySQL 8.0.16, CREATE TABLE consente le funzionalità principali dei vincoli CHECK di tabella e colonna, per tutti i motori di archiviazione. CREATE TABLE consente la seguente sintassi del vincolo CHECK, sia per i vincoli di tabella che per quelli di colonna

Documentazione sui controlli MySQL


-2

prova con set sql_mode = 'STRICT_TRANS_TABLES'ORSET sql_mode='STRICT_ALL_TABLES'


2
che actall non aiuta (MySQL 5.6) impedisce di inserire dati di tipo falso ma non di inserire dati che non soddisfano il CHECKvincolo
petermeissner,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.