MySQLのCHECK制約が機能しない


126

まず、次のようなテーブルを作成しました

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

そして、そのテーブルに値を挿入しました

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

MySQLはエラーを表示せず、値を受け入れました。


部分的に同意します。あなたがそれを使おうとしたのであれば、あなたは両方の質問をしていると考えられます。実際、あなたが受け入れた答えは主にそれが機能しない理由を説明しています。
igorrs 2013年

1
この機能リクエストにバグを投票できます:bugs.mysql.com/bug.php?id=3464ですが、10年間注目されていません。
Jared Beck

11
MariaDBでバージョン10.2.1以降のCHECK制約を使用できます。
joanq 2016年

回答:


140

MySQL 8.0.16は、CHECK制約をサポートする最初のバージョンです。

https://dev.mysql.com/doc/refman/8.0/en/create-table-check-constraints.htmlをお読みください

MySQL 8.0.15以前を使用している場合、MySQLリファレンスマニュアルには次のように記載されています

CHECK句は、すべてのストレージエンジンによって解析されますが、無視されます。

トリガーを試してください...

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 ;

お役に立てば幸いです。


9
ここでは、代わりにエラーをトリガする方法を見つける:stackoverflow.com/a/7189396/1144966
petermeissner

41
これは、MySQLの代わりに常にPostgreSQLを使用するという選択の幅が広がっている理由の大きな輝きの1つです。
Reinderien 2014

5
パーサーがCHECK定義された制約に遭遇した場合に警告をスローするのは、MySQLでの開発が10分か15分かと思います。ああ、それはあまりにも簡単です...
gaborsch

75

残念ながら、MySQLはSQLチェック制約をサポートしていません。互換性の理由からDDLクエリで定義できますが、無視されるだけです。

簡単な選択肢があります

エラーを発生させるか、データの要件が満たされていない場合にフィールドをデフォルト値に設定するトリガーを作成BEFORE INSERTしてBEFORE UPDATEトリガーできます。

BEFORE INSERTMySQL 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 ;  

MySQL 5.5より前では、エラーを引き起こす必要がありました。たとえば、未定義のプロシージャを呼び出します。

どちらの場合も、これにより暗黙のトランザクションロールバックが発生します。MySQLでは、プロシージャおよびトリガー内でのROLLBACKステートメント自体は許可されていません。

トランザクションをロールバックしたくない場合(INSERT / UPDATEは、「チェック制約」が失敗した場合でもパスする必要があります。値を上書きしてSET NEW.ID = NULL、IDをフィールドのデフォルト値に設定できますが、実際にはIDには意味がありません。 tho

編集: 抜けた引用を削除しました。

:=オペレーターに関して:

とは異なり=:=演算子は比較演算子として解釈されません。つまり:=、(SETステートメントだけでなく)有効なSQLステートメントで変数に値を割り当てることができます。

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

バックティック識別子の引用について:

識別子の引用文字はバックティック(「 `」)です

ANSI_QUOTES SQLモードが有効になっている場合は、二重引用符で識別子を引用することもできます。

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


7
...少なくともCHECK :(。Coupla tutes:net.tutsplus.com/tutorials/databases/…と比較すると、それほど単純ではありません。sitepoint.com / how
Ben

これは非常に大きく見えます。私は、私はむしろでこれを置くのではなく、そこのpythonとチェック値のタプルを作成すると思います。
OzzyTheGiant

簡単な質問:これを設定しないと機能しないのはなぜDELIMITERですか?
ddz 2017年

52

CHECK ドキュメントのごくわずかなコメントで説明されているように、MySQLでは制約は無視されます。 CREATE TABLE

CHECK句は、すべてのストレージエンジンによって解析されますが、無視されます。


2
@thefiloe:正しい、CHECK制約が適切に実装された他のDBMS では、がCHECK評価されたFALSE場合、挿入(または更新)は行われず、エラーが発生します。
ypercubeᵀᴹ

MariaDBで修正されました(この回答を参照してくださいstackoverflow.com/a/44333349)。
ジェローム

@Jérôme私は知っています。この分野の改善を含むいくつかの(より最近の)回答があります(MariaDBとMySQLの両方で、MariaDBがCHECK制約を適切に実装する前に、この問題を回避する他の方法がありました)。私が確信していないのは、私が行って古い答えをすべて編集する必要があるかどうかです!
ypercubeᵀᴹ

最近の回答へのリンクを含む私のコメントは問題ないと思います。または何もないよりはましだ。たぶん私は編集するべきでした。私はあなたに何かをするよう圧力をかけるつもりはありませんでした。
ジェローム2018



1

チェック制約はバージョン8.0.15でサポートされています(まだリリースされていません)。

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

[1月23日16:24]ポールデュボア

開発者による投稿:8.0.15で修正されました。

以前は、MySQLは限定された形式のCHECK制約構文を許可していましたが、構文解析して無視していました。MySQLは現在、すべてのストレージエンジンに対して、テーブルと列のCHECK制約のコア機能を実装しています。制約は、CREATE TABLEおよびALTER TABLEステートメントを使用して定義されます。


1

MySQL 8.0.16にアップデートして使用しますchecks

MySQL 8.0.16以降、CREATE TABLEはすべてのストレージエンジンに対して、テーブルとカラムのCHECK制約のコア機能を許可します。CREATE TABLEは、テーブル制約と列制約の両方に対して、次のCHECK制約構文を許可します

MySQLチェックのドキュメント


-2

set sql_mode = 'STRICT_TRANS_TABLES'ORで試すSET sql_mode='STRICT_ALL_TABLES'


2
そのactuallは役に立たない(MySQL 5.6)、false型のデータの入力を防止するが、CHECK制約を満たさないデータの入力を防止しない
petermeissner
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.