6

MySQL 5.6 InnoDb で実行時に NOT NULL 外部キーを無視するという問題が発生していますINSERT INTO xxx (col) SELECT ...。他の形式で挿入ステートメントを実行すると、制約が適切に適用されます。外部キー チェックが有効であり、かつsql_mode = STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ENGINE_SUBSTITUTION

次に例を示します。

CREATE TABLE Test_Parent
(
    id BIGINT(18) UNSIGNED PRIMARY KEY NOT NULL AUTO_INCREMENT,
    dummy VARCHAR(255)
) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_unicode_ci
    COMMENT 'Test parent table';

CREATE TABLE Test_Child
(
    id BIGINT(18) unsigned PRIMARY KEY NOT NULL AUTO_INCREMENT,
    fid BIGINT UNSIGNED NOT NULL,
    FOREIGN KEY Fk_Test_Parent_01(fid) REFERENCES Test_Parent(id)
) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_unicode_ci
    COMMENT 'Test child table';

INSERT INTO Test_Parent(dummy)
VALUES ('test');

## Here's where the FK constraint should be enforced but isn't ##
INSERT INTO Test_Child(fid)
SELECT id
    FROM Test_Parent
WHERE dummy = 'missing value';

1 row affected in 5ms

## Running an insert with a different format, the constraint is enforced ##
INSERT INTO Test_Child(fid)
VALUES (null);
Column 'fid' cannot be null

## Running this format, the foreign key is also enforced ##
INSERT INTO Test_Child(id, fid)
VALUES (123, (SELECT id FROM Test_Parent WHERE dummy = 'missing value'));
Column 'fid' cannot be null

MySQL が 3 つの挿入ステートメントのうち 2 つに外部キーを適用する理由がわかりません。何か案は?

4

1 に答える 1

1

クライアントからの誤解を招く1 row affected in 5msメッセージは、ここで混乱の元になる可能性があります。コメント スレッドで、IntelliJ がそのメッセージを報告していると述べましたが、明確に定義されたテスト テーブルを MySQL 5.6.35 と 5.7.16-ubuntu の両方で実行しました。両方のバージョンで、問題のステートメントは影響を受ける行が 0 であると報告しました。

mysql > INSERT INTO Test_Child(fid)
    -> SELECT id
    ->     FROM Test_Parent
    -> WHERE dummy = 'missing value';
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

したがって、誤解を招くような影響を受ける行のメッセージを見渡すと、ここで実際に起こっていることはSELECT、ステートメントの一部がINSERT...SELECT行と一致しないため、MySQL は行を挿入しようとしません。したがって、外部キー制約違反はありませんでした。

の形式は、INSERT INTO...SELECT後の例とは少し異なります。

INSERT INTO Test_Child(id, fid)
VALUES (123, (SELECT id FROM Test_Parent WHERE dummy = 'missing value'));

...この場合、数値リテラルは 1 行の挿入を強制し、副選択から返され123た値とペアになっているためです。nullそのnullため、挿入が試行され、制約違反が発生します。

null 値を含む行を強制的INSERT...SELECTに返すと、制約違反のために失敗する可能性があります。

INSERT INTO Test_Child (fid)
-- Return a literal NULL row...
SELECT NULL as id FROM Test_Parent
-- Column fid cannot be null
于 2016-12-23T01:00:21.357 に答える