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


235

他のテーブルへのID列がいくつかあるテーブルがあります。

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

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

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


6
MySQLについては知りませんが、MS SQL Serverでは、必要なセマンティクスで外部キーをnullにすることができます。これは標準的な動作です。
Jeffrey L Whitledge、2010年

1
外部キー。mySQLではデフォルトでnullにできません。理由は単純です。何かを参照してnullにすると、データの整合性が失われます。テーブルセットを作成するときに、nullをNOTにしてから、外部キー制約を適用します。更新時にnullを設定することはできません。エラーが送信されますが、この列を更新せず、変更する必要のあるフィールドのみを更新することはできます(必須)。
JoelBonetR 2016年

回答:


245

はい、値が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`))

にNULLを挿入するため、最初の挿入は成功しますparent_idparentテーブルに存在しない値を挿入しようとしたため、2番目の挿入は外部キー制約のために失敗します。


16
親テーブルは、ID INT NOT NULLで宣言することもできます。
ウィル

@CJDennis 1つの行だけがnull IDを持つことができるようにすると、他の行のフォールバック値として使用できます。(列を多く使用する場合は、DBの方がうまく機能する可能性があります。)値が最初に「デフォルト」(nullを使用して)に設定されたか、またはたまたま「デフォルト」と同じ値。nullのIDを持つ行を作成することにより、この行が通常の行として使用されないことを明確に示し、他の行に動的なデフォルト値の一種を提供する方法としてその行を使用できます。
ウロボロス2017

1
parent_id INT NULLパートは(parent_id int default null

Javaユーザー向けの注意点です。クラスメンバーのint代わりにibatisまたは他のORMを使用してプリミティブを使用するとInteger、デフォルトはnullにならず、0になり、制約に失敗します。
ジムフォード

32

挿入するとき、null列の値は特にNULLとして宣言する必要があることを発見しました。そうでない場合、(空の文字列ではなく)制約違反エラーが発生します。


8
これを許可するために列にデフォルト値のNULLを設定できませんか?
Kevin Coulombe 2013年

はい、ほとんどの言語でNULLは空の文字列とは異なります。おそらく最初は微妙ですが、覚えておくことが重要です。
ゲーリー、

バックスライダー、「(空の文字列ではなく)」と言いますが、空の文字列の値を挿入するつもりはなかったと思いますが、Value atに値を指定しないでください。すべて?つまり、あなたはあなたの中で列に言及していませんINSERT INTO {table} {list_of_columns}か?それは私にも当てはまるからです。列の言及を省略するとエラーが発生しますが、NULLを含めて明示的にNULLに設定するとエラーが修正されます。私が正しければ、@ Garyのコメントは当てはまらないと思います(空の文字列を意味しなかったためです)が、@ Kevin Coulombeのコメントは役に立ちます...
The Red Pea

はい、@ KevinCoulombeの提案は機能します。ここで
The Red Pea

NULL外部キーを含むレコードを更新するときに明示的である根拠は文字列型(varcharなど)にのみ適用されることを指摘することが重要です。それ以外の場合は、空の文字列をデフォルトとして渡すことができます。これはMySQLの場合であり、更新時に整合性エラーが発生します。
CodeMantle

4

はい、期待どおりに動作します。残念ながら、MySQLのマニュアルでこれに関する明示的な説明を見つけるのに苦労しているようです。

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


設計上、外部キーはNULLではないいくつかのキー(プライマリ)を参照する必要がありますが、開発段階では、最初に複数のデータを子テーブルに挿入する必要があります。 。そのため、NULL値を許可しています。NULLを持つプロダクションでは、デザインフローになります。
vimal krishna 2015

2

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

4
「上記」とはどういう意味ですか?別の回答を参照している場合、順序が変わる可能性があることに注意してください。
d219

2

はい、値はNULLにすることができますが、明示する必要があります。私は以前に同じ状況を経験しましたが、なぜこれが起こるのか忘れがちですので、何をする必要があるかを覚えるのに少し時間がかかります。

送信されたデータが空の文字列としてキャストまたは解釈されると、失敗します。ただし、INSERTINGまたはUPDATINGの際に明示的に値をNULLに設定することで、問題ありません。

でも、これがプログラミングの面白さですね。独自の問題を作成して修正する!乾杯!


1

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


2
これは同じことではありません。デフォルト値または「ニュートラル」値はNULLと同じではなく、値がありません。NULLよりもデフォルト値のメリットを議論しないと、あなたの言い回しは少し混ざったものになります。以上のような何か「これを回避する別の方法は、他のテーブルにDEFAULT要素を挿入するだろう」と言うべきです「これを回避する別の方法は、他のテーブル内のヌル要素を挿入することであろう」
blindguy

0

この問題にもこだわりました。しかし、私は外部キーをと定義するだけで解決しました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;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.