とにかく、常に1が値を必要とする2つのnull値の制約を持つことはありますか?たとえば、2つの日付列はどちらもnullですが、値が必要な少なくとも 1です。
Expenseというテーブルがあるとします
そして2つの日付があります:
prevision_expense_expiration_date DATE NULLABLEense_payment_date DATE NULLABLE
これら2つの列のロジックは次のとおりです。
私は何かを購入しましたが、電話代のような日付で支払う必要があることはわかっています。私はこれをexpense_payment_dateとともに費用として入力します。この日付は支払予定日ですが、請求書の有効期限のような実際の支払い日ではありません。
他の状況では、あるサービスのギフトカードを販売しています。私はmayクライアントに転送されたサービスをプロバイダーに購入する費用がありますonlyクライアントがカードを利用する場合。したがって、ギフトカードには有効期限があります。ギフトカードが有効な期間の費用として挿入せずに、その「費用」を予測します。ギフトカードの有効期限が切れた場合、その「費用」はアカウントに入力しないでくださいシステム。
Prevision_expenseとconfirm_expenseと呼ばれる2つの同等のテーブルを使用できることはわかっていますが、正しくないため、同じテーブルに2つの日付があり、null値を指定できますが、常に必要になるように制約または何かしたいのです。
別の可能な戦略があります:
payment_date DATE NOT NULL is_prevision_date BOOL NOT NULL
したがって、この場合、日付が規定値である場合、ブール値は1になります。それ以外の場合は0になります。null値はなく、すべて良好です。例外として、最初に準備日があり、THEN(2日後と言います)にその費用の確認日があるときに、両方の値を保存するオプションが必要です。この場合、戦略2では、そのオプションはありません。
私はデータベース設計ですべてを間違っていますか? :D
JDシュミットの回答のバージョンですが、余分な列のぎこちなさはありません。
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
SQL Serverを使用している場合は、テーブルで永続的な計算列を使用することで、トリガーの使用を回避できます。
CREATE TABLE Test_Constraint
(
A DateTime Null,
B DateTime Null,
A_and_B AS (CASE WHEN A IS Null AND B IS Null THEN Null ELSE Convert(Binary(1), 1) END) PERSISTED Not Null
);
計算列A_and_Bのcaseステートメントは、列AとBの両方がnullの場合、null値を返しますが、計算列のNot Null制約により、挿入を妨げるエラーが発生します。それ以外の場合は1を返します。
計算列は永続化されるため、テーブルに物理的に格納されます。バイナリに変換すると、この影響が最小限に抑えられ、列が長さ1のバイナリデータ型になります。
同じように見える記事を見つけた here
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//
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