他のテーブルへの複数のID列を持つテーブルがあります。
外部キーが整合性を強制するようにしたいのみデータをそこに入れた場合。後で更新してその列にデータを入力する場合、制約もチェックする必要があります。
(これはデータベースサーバーに依存している可能性が高いため、MySQLとInnoDBテーブルタイプを使用しています)
これは妥当な期待だと思いますが、間違っている場合は修正してください。
はい、値がNULLでない場合にのみ制約を実施できます。これは、次の例で簡単にテストできます。
CREATE DATABASE t;
USE t;
CREATE TABLE parent (id INT NOT NULL,
PRIMARY KEY (id)
) ENGINE=INNODB;
CREATE TABLE child (id INT NULL,
parent_id INT NULL,
FOREIGN KEY (parent_id) REFERENCES parent(id)
) ENGINE=INNODB;
INSERT INTO child (id, parent_id) VALUES (1, NULL);
-- Query OK, 1 row affected (0.01 sec)
INSERT INTO child (id, parent_id) VALUES (2, 1);
-- ERROR 1452 (23000): Cannot add or update a child row: a foreign key
-- constraint fails (`t/child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY
-- (`parent_id`) REFERENCES `parent` (`id`))
parent_id
にNULLを挿入するため、最初の挿入は成功します。 parent
テーブルに存在しない値を挿入しようとしたため、2番目の挿入は外部キー制約のため失敗します。
挿入時に、null列の値をNULLとして明示的に宣言する必要があることがわかりました。そうしないと、(空の文字列ではなく)制約違反エラーが発生します。
はい、期待通りに機能します。残念ながら、 MySQLマニュアル でこのことを明示的に説明するのに苦労しているようです。
外部キーは、値が他のテーブルに存在する必要があることを意味します。 NULL は値が存在しないことを意味するため、列をNULLに設定すると、その列に制約を適用しようとする意味がなくなります。
これを回避する別の方法は、もう一方のテーブルにDEFAULT要素を挿入することです。たとえば、他のテーブルのuuid = 00000000-0000-0000-0000-000000000000への参照は、アクションがないことを示します。また、そのIDのすべての値を「中立」に設定する必要があります。 0、空の文字列、コードロジックに影響を与えないためにnull。
上記は機能しますが、これは機能しません。 ON DELETE CASCADEに注意してください
CREATE DATABASE t;
USE t;
CREATE TABLE parent (id INT NOT NULL,
PRIMARY KEY (id)
) ENGINE=INNODB;
CREATE TABLE child (id INT NULL,
parent_id INT NULL,
FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE
) ENGINE=INNODB;
INSERT INTO child (id, parent_id) VALUES (1, NULL);
-- Query OK, 1 row affected (0.01 sec)
私もこの問題にこだわった。しかし、外部キーをunsigned integer
として定義するだけで解決しました。以下の例を見つけます
CREATE TABLE parent (
id int(10) UNSIGNED NOT NULL,
PRIMARY KEY (id)
) ENGINE=INNODB;
CREATE TABLE child (
id int(10) UNSIGNED NOT NULL,
parent_id int(10) UNSIGNED DEFAULT NULL,
FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE
) ENGINE=INNODB;