web-dev-qa-db-ja.com

外部キーを持つテーブル列をNULLにできますか?

他のテーブルへの複数のID列を持つテーブルがあります。

外部キーが整合性を強制するようにしたいのみデータをそこに入れた場合。後で更新してその列にデータを入力する場合、制約もチェックする必要があります。

(これはデータベースサーバーに依存している可能性が高いため、MySQLとInnoDBテーブルタイプを使用しています)

これは妥当な期待だと思いますが、間違っている場合は修正してください。

188
bender

はい、値が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番目の挿入は外部キー制約のため失敗します。

189
Daniel Vassallo

挿入時に、null列の値をNULLとして明示的に宣言する必要があることがわかりました。そうしないと、(空の文字列ではなく)制約違反エラーが発生します。

24
Backslider

はい、期待通りに機能します。残念ながら、 MySQLマニュアル でこのことを明示的に説明するのに苦労しているようです。

外部キーは、値が他のテーブルに存在する必要があることを意味します。 NULL は値が存在しないことを意味するため、列をNULLに設定すると、その列に制約を適用しようとする意味がなくなります。

3
davidtbernal

これを回避する別の方法は、もう一方のテーブルにDEFAULT要素を挿入することです。たとえば、他のテーブルのuuid = 00000000-0000-0000-0000-000000000000への参照は、アクションがないことを示します。また、そのIDのすべての値を「中立」に設定する必要があります。 0、空の文字列、コードロジックに影響を与えないためにnull。

1
Wildhammer

上記は機能しますが、これは機能しません。 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)
1
MrFabulous

私もこの問題にこだわった。しかし、外部キーを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;
0
Shams Reza