2016-12-23 24 views
6

У меня проблема с MySQL 5.6 InnoDb, игнорируя внешний ключ NOT NULL при запуске INSERT INTO xxx (col) SELECT .... Ограничение принудительно выполняется при запуске операторов insert в других форматах. Внешние ключ проверки включены, и sql_mode = STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ENGINE_SUBSTITUTIONMySQL Вставка Выберите не принудительно NULL Constraint

Вот пример:

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 будет применять внешний ключ для 2 из утверждений 3 вставки. Есть идеи?

+1

Интересно, если вы видите на доложено «1 ряд пострадавших», потому что 'INSERT ... SELECT' на самом деле не приводит к вставке любой строки, потому что предложение' WHERE' не соответствует. Если я 'SELECT *' из обеих таблиц, я не вижу строк в 'Test_Child' ... http: //sqlfiddle.com/#! 9/7413e0/1 –

+0

То есть, если ваши реальные данные и случай использования существенно не отличаются от тест, который вы настроили для нас. –

+0

Правильно - он сообщает 1 строку как вставленную, но ничего не было вставлено в таблицу. Я ожидаю, что в этом сценарии будет применено ограничение NOT NULL. Вместо этого, как будто исключение проглатывается. – adam

ответ

1

Возможно, сообщение об ошибке вашего клиента может стать источником путаницы. В потоке комментариев, о котором вы говорили, 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-оператора не содержит строк, поэтому MySQL не пытается вставить какую-либо строку. Следовательно, нарушение ограничений внешнего ключа не было.

Формат INSERT INTO...SELECT немного отличается от вашего последующего примера:

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

... потому что в этом случае числовые литералы 123 силы один ряд должен быть вставлен, и он работает в паре с 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 

 Смежные вопросы

  • Нет связанных вопросов^_^