2016-12-23 5 views
6

INSERT INTO xxx (col) SELECT ...を実行しているときに、NOT NULL外部キーを無視しているMySQL 5.6 InnoDbに問題があります。この制約は、他の形式のinsert文を実行するときに適切に適用されます。外部キーチェックが有効になっている、とsql_mode = STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ENGINE_SUBSTITUTIONMySQL Insert SelectがNOT NULL制約を強制しない

はここに例を示します

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のための外部キーを強制されますなぜ私は理解していません。何か案は?

+1

そのため、 'WHERE'節が一致しないので、' INSERT ... SELECT'は実際に行挿入を行いません。両方のテーブルから 'SELECT *'を実行した場合、 'Test_Child'には行がありません。http://sqlfiddle.com/#!9/7413e0/1 –

+0

実際のデータとユースケースがあなたが私たちのために設定したテストセット。 –

+0

これは正しいことです.1行が挿入されたと報告しますが、実際にはテーブルに何も挿入されていません。私は、このシナリオで強制されるべき 'NOT NULL'制約があると思います。代わりに、それは例外が飲み込まれたかのようです。 – adam

答えて

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 

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

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

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

...この場合には、数値リテラル123力1行が挿入されるように、それはnullと対になっているので、副選択から戻された値。そのため、nullが挿入しようとしており、制約違反が発生します。

あなたはNULL値を持つ行を返すようにINSERT...SELECTを強制する場合は、あなたが原因制約違反のために失敗することができます:あなたは、「影響を受けた1行」誤って報告を見ている場合、私は疑問に思う

INSERT INTO Test_Child (fid) 
-- Return a literal NULL row... 
SELECT NULL as id FROM Test_Parent 
-- Column fid cannot be null 
関連する問題