質問
fieldAとfieldBの両方をNULLにできないように、MySQLで非NULL制約を作成する最良の方法は何ですか。他のフィールドにNULL以外の値がある限り、どちらか一方がNULLであってもかまいません。そして、両方にNULL以外の値がある場合、さらに優れています。
解決
MySQL 5.5では SIGNAL が導入されたため、ビル・カーウィンの答えにもう列が必要です。ビルは、更新のトリガーも必要だと指摘したので、それも含めました。
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
他のヒント
これは質問に対する直接的な回答ではなく、追加情報です。
複数の列を処理し、すべてがヌルであるか、1つがヌルではないかを確認するとき、通常は 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の両方をテストしました。その後、SHOW CREATE TABLEを使用すると、テーブルを定義したときにエラーが発生しなかったにもかかわらず、CHECK制約がテーブル定義にないことがわかります。
これは、 MySQLマニュアルと一致します。 " CHECK句は解析されますが、すべてのストレージエンジンで無視されます。
したがって、MySQLの場合、トリガーを使用してこのルールを強制する必要があります。唯一の問題は、MySQLトリガーにエラーを発生させたり、INSERT操作を中止する方法がないことです。エラーを引き起こすためにトリガーでできることの1つは、NOT NULL列を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はその後制約を至福に無視します
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つのテーブル内の列のみをチェックできることに注意してください。