Die CHECK-Einschränkung in MySQL funktioniert nicht

126

Zuerst habe ich eine Tabelle wie erstellt

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

und dann Werte in diese Tabelle eingefügt

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

MySQL zeigt keinen Fehler an, es hat die Werte akzeptiert.

John Raja
quelle
Teilweise zustimmen. Da Sie versucht haben, es zu verwenden, kann davon ausgegangen werden, dass Sie beide Fragen gestellt haben. In der Tat erklärt die Antwort, die Sie akzeptiert haben, hauptsächlich, warum es nicht funktioniert.
Igorrs
1
Sie können über diese Funktionsanfrage abstimmen: bugs.mysql.com/bug.php?id=3464, aber sie hat seit einem Jahrzehnt keine Aufmerksamkeit mehr erhalten.
Jared Beck
11
Sie können CHECK-Einschränkungen in MariaDB ab Version 10.2.1 verwenden .
Joanq

Antworten:

140

MySQL 8.0.16 ist die erste Version, die CHECK-Einschränkungen unterstützt.

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

Wenn Sie MySQL 8.0.15 oder früher verwenden, heißt es im MySQL-Referenzhandbuch :

Die CHECKKlausel wird analysiert, aber von allen Speicher-Engines ignoriert.

Versuchen Sie einen Auslöser ...

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 ;

Hoffentlich hilft das.

David Kerins
quelle
9
Hier finden Sie, wie Sie stattdessen einen Fehler auslösen können: stackoverflow.com/a/7189396/1144966
petermeissner
41
Dies ist einer der großen Gründe, warum ich immer PostgreSQL anstelle von MySQL verwenden werde, wenn ich die Wahl habe.
Reinderien
5
Ich frage mich, ob es in MySQL eine 10-minütige oder 15-minütige Entwicklung wäre, eine Warnung auszulösen, wenn der Parser auf eine CHECKdefinierte Einschränkung stößt . Ahhh, das wäre zu einfach ...
gaborsch
75

Leider unterstützt MySQL keine SQL-Überprüfungsbeschränkungen. Sie können sie aus Kompatibilitätsgründen in Ihrer DDL-Abfrage definieren, sie werden jedoch einfach ignoriert.

Es gibt eine einfache Alternative

Sie können erstellen BEFORE INSERTundBEFORE UPDATE auslösen, die entweder einen Fehler verursachen oder das Feld auf den Standardwert setzen, wenn die Anforderungen der Daten nicht erfüllt sind.

Beispiel für die BEFORE INSERTArbeit nach 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 ;  

Vor MySQL 5.5 mussten Sie einen Fehler verursachen, z. B. eine undefinierte Prozedur aufrufen.

In beiden Fällen führt dies zu einem impliziten Transaktions-Rollback. MySQL erlaubt die ROLLBACK-Anweisung selbst nicht innerhalb von Prozeduren und Triggern.

Wenn Sie die Transaktion nicht zurücksetzen möchten (INSERT / UPDATE sollte auch bei einer fehlgeschlagenen "Prüfbedingung" erfolgreich sein, können Sie den Wert überschreiben, mit SET NEW.ID = NULLdem die ID auf den Standardwert des Felds gesetzt wird. Dies ist für eine ID nicht wirklich sinnvoll tho

Bearbeiten: Das streunende Zitat wurde entfernt.

In Bezug auf den :=Betreiber:

Im Gegensatz dazu =wird der :=Operator niemals als Vergleichsoperator interpretiert. Dies bedeutet, dass Sie :=in jeder gültigen SQL-Anweisung (nicht nur in SET-Anweisungen) einer Variablen einen Wert zuweisen können.

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

In Bezug auf Backtick-ID-Anführungszeichen:

Das Bezeichner-Anführungszeichen ist das Backtick ("` ")

Wenn der SQL-Modus ANSI_QUOTES aktiviert ist, können Bezeichner auch in doppelte Anführungszeichen gesetzt werden

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

Michel Feldheim
quelle
7
... nicht sehr einfach, zumindest im Vergleich zu CHECK :(. Coupla tutes: net.tutsplus.com/tutorials/databases/… , sitepoint.com/how-to-create-mysql-triggers
Ben
ugh das sieht sehr sperrig aus. Ich denke, ich erstelle lieber ein Tupel in Python und überprüfe dort die Werte, anstatt dies
einzugeben
Kurze Frage: Warum funktioniert das nicht, ohne das einzustellen DELIMITER?
ddz
52

CHECK Einschränkungen werden von MySQL ignoriert, wie in einem winzigen Kommentar in den Dokumenten erläutert: CREATE TABLE

Die CHECKKlausel wird analysiert, aber von allen Speicher-Engines ignoriert.

ypercubeᵀᴹ
quelle
2
@thefiloe: Richtig, in anderen DBMS mit korrekter Implementierung von CHECKEinschränkungen, wenn die CHECKAuswertung bis FALSEdahin das Einfügen (oder Aktualisieren) nicht erfolgt und ein Fehler verursacht wird.
Ypercubeᵀᴹ
In MariaDB behoben (siehe diese Antwort stackoverflow.com/a/44333349 ).
Jérôme
@ Jérôme Ich weiß, ich habe einige (neuere) Antworten, die Verbesserungen in diesem Bereich beinhalten (es gab andere Möglichkeiten, dieses Problem zu umgehen, sowohl in MariaDB als auch in MySQL, bevor MariaDB die CHECK-Einschränkungen ordnungsgemäß implementiert hat). Ich bin mir nicht sicher, ob ich alle meine alten Antworten bearbeiten soll!
Ypercubeᵀᴹ
Ich nehme an, mein Kommentar mit einem Link zu einer neueren Antwort ist in Ordnung. Oder besser als nichts. Vielleicht hätte ich bearbeiten sollen. Ich wollte dich nicht unter Druck setzen, irgendetwas zu tun.
Jérôme
1

Check-Einschränkungen werden ab Version 8.0.15 unterstützt (müssen noch veröffentlicht werden).

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

[23. Januar 16:24] Paul Dubois

Gepostet vom Entwickler: Behoben in 8.0.15.

Zuvor erlaubte MySQL eine eingeschränkte Form der CHECK-Einschränkungssyntax, analysierte sie jedoch und ignorierte sie. MySQL implementiert jetzt die Kernfunktionen der Tabellen- und Spalten-CHECK-Einschränkungen für alle Speicher-Engines. Einschränkungen werden mit den Anweisungen CREATE TABLE und ALTER TABLE definiert.

James
quelle
1

Aktualisieren Sie auf MySQL 8.0.16, um Folgendes zu verwenden checks:

Ab MySQL 8.0.16 ermöglicht CREATE TABLE die Kernfunktionen der Tabellen- und Spalten-CHECK-Einschränkungen für alle Speicher-Engines. CREATE TABLE ermöglicht die folgende CHECK-Einschränkungssyntax sowohl für Tabelleneinschränkungen als auch für Spalteneinschränkungen

MySQL prüft die Dokumentation

sdlins
quelle
-2

versuchen Sie es mit set sql_mode = 'STRICT_TRANS_TABLES'ODERSET sql_mode='STRICT_ALL_TABLES'

Kanagu
quelle
2
das eigentlich hilft nicht (MySQL 5.6) es verhindert die Eingabe von Daten vom falschen Typ, aber nicht von der Eingabe von Daten, die die CHECKEinschränkung nicht erfüllen
petermeissner