2016-12-23 7 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

그 때문에 INSERT ... SELECT는'WHERE' 절이 일치하지 않기 때문에 실제로 어떤 행 삽입도 일어나지 않습니다. 두 테이블 모두에서'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-우분투에서 잘 정의 된 테스트 테이블을 실행했으며 두 버전 모두 영향을받은 행이 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의 형식이 나중에 예에서 조금 차이가

:이 경우, 숫자 문자 123 힘을 하나 개의 행을 삽입 할 수 있기 때문에 ...

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

하고는 null와 페어링되어 subselect에서 리턴 된 값. 따라서 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