fieldA と fieldB の両方を NULL にできないように、MySQL で非 NULL 制約を作成する最良の方法は何ですか? もう一方のフィールドに NULL 以外の値が含まれている限り、どちらかがそれ自体で NULL であるかどうかは気にしません。両方とも NULL 以外の値を持っている場合は、さらに優れています。
6 に答える
これはあなたの質問に対する直接の答えではありませんが、いくつかの追加情報です。
複数の列を処理し、すべてがnullであるか、1つがnullでないかを確認する場合、通常は次COALESCE()
のように使用します。リストが大きくなった場合は、簡潔で読みやすく、簡単に保守できます。
COALESCE(a, b, c, d) IS NULL -- True if all are NULL
COALESCE(a, b, c, d) IS NOT NULL -- True if any one is not null
これはトリガーで使用できます。
@Sklivvz:MySQL 5.0.51aでテストすると、CHECK制約が解析されますが、強制されません。エラーなしで(NULL、NULL)を挿入できます。MyISAMとInnoDBの両方をテストしました。続いてSHOWCREATETABLEを使用すると、テーブルを定義したときにエラーが発生しなかったにもかかわらず、CHECK制約がテーブル定義に含まれていないことがわかります。
これは、 「CHECK句は解析されますが、すべてのストレージエンジンで無視されます」というMySQLのマニュアルと一致します。
したがって、MySQLの場合、このルールを適用するにはトリガーを使用する必要があります。唯一の問題は、MySQLトリガーにエラーを発生させたりINSERT操作を中止したりする方法がないことです。エラーを発生させるためにトリガーで実行できることの1つは、NOTNULL列をNULLに設定することです。
CREATE TABLE foo (
FieldA INT,
FieldB INT,
FieldA_or_FieldB TINYINT NOT NULL;
);
DELIMITER //
CREATE TRIGGER FieldABNotNull BEFORE INSERT ON foo
FOR EACH ROW BEGIN
IF (NEW.FieldA IS NULL AND NEW.FieldB IS NULL) THEN
SET NEW.FieldA_or_FieldB = NULL;
ELSE
SET NEW.FieldA_or_FieldB = 1;
END IF;
END//
INSERT INTO foo (FieldA, FieldB) VALUES (NULL, 10); -- OK
INSERT INTO foo (FieldA, FieldB) VALUES (10, NULL); -- OK
INSERT INTO foo (FieldA, FieldB) VALUES (NULL, NULL); -- gives error
更新前にも同様のトリガーが必要です。
MySQL 5.5 ではSIGNALが導入されたため、Bill Karwin の回答に余分な列は必要ありません。ビルは更新のトリガーも必要だと指摘したので、それも含めました。
CREATE TABLE foo (
FieldA INT,
FieldB INT
);
DELIMITER //
CREATE TRIGGER InsertFieldABNotNull BEFORE INSERT ON foo
FOR EACH ROW BEGIN
IF (NEW.FieldA IS NULL AND NEW.FieldB IS NULL) THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = '\'FieldA\' and \'FieldB\' cannot both be null';
END IF;
END//
CREATE TRIGGER UpdateFieldABNotNull BEFORE UPDATE ON foo
FOR EACH ROW BEGIN
IF (NEW.FieldA IS NULL AND NEW.FieldB IS NULL) THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = '\'FieldA\' and \'FieldB\' cannot both be null';
END IF;
END//
DELIMITER ;
INSERT INTO foo (FieldA, FieldB) VALUES (NULL, 10); -- OK
INSERT INTO foo (FieldA, FieldB) VALUES (10, NULL); -- OK
INSERT INTO foo (FieldA, FieldB) VALUES (NULL, NULL); -- gives error
UPDATE foo SET FieldA = NULL; -- gives error
これはそのような制約の標準的な構文ですが、MySQL は後で制約を無視します。
ALTER TABLE `generic`
ADD CONSTRAINT myConstraint
CHECK (
`FieldA` IS NOT NULL OR
`FieldB` IS NOT NULL
)
私はSQL Serverで同様のことをしました.MySQLで直接動作するかどうかはわかりませんが、
ALTER TABLE tableName ADD CONSTRAINT constraintName CHECK ( (fieldA IS NOT NULL) OR (fieldB IS NOT NULL) );
少なくとも私はそれが構文だと信じています。
ただし、複数のテーブルにわたってチェック制約を作成することはできないことに注意してください。チェックできるのは 1 つのテーブル内の列のみです。