[НОВ ОТГОВОР]
Благодаря на @NeverEndingQueue, че повдигна това. Изглежда MySQL най-накрая е отстранил този проблем. Не съм сигурен в коя версия за първи път беше отстранен този проблем, но в момента тествах със следната версия и проблемът вече не е там:
mysql> SHOW VARIABLES LIKE "%version%";
+-------------------------+------------------------------+
| Variable_name | Value |
+-------------------------+------------------------------+
| innodb_version | 5.7.22 |
| protocol_version | 10 |
| slave_type_conversions | |
| tls_version | TLSv1,TLSv1.1 |
| version | 5.7.22 |
| version_comment | MySQL Community Server (GPL) |
| version_compile_machine | x86_64 |
| version_compile_os | Linux |
+-------------------------+------------------------------+
За да бъде ясно:
mysql> INSERT IGNORE INTO child -> VALUES -> (NULL, 1) -> , (NULL, 2) -> , (NULL, 3) -> , (NULL, 4) -> , (NULL, 5) -> , (NULL, 6); Query OK, 4 rows affected, 2 warnings (0.03 sec) Records: 6 Duplicates: 2 Warnings: 2
За да разберете по-добре значението на тази последна заявка и защо тя показва, че проблемът е отстранен, моля, продължете със стария отговор по-долу.
[СТАР ОТГОВОР]
Моето решение е заобикаляне на проблема и действителното решение винаги ще бъде отстраняване на проблема в самия MySQL.
Следните стъпки решиха проблема ми:
а. Помислете за наличието на следните таблици и данни:
mysql>
CREATE TABLE parent (id INT AUTO_INCREMENT NOT NULL
, PRIMARY KEY (id)
) ENGINE=INNODB;
mysql>
CREATE TABLE child (id INT AUTO_INCREMENT
, parent_id INT
, INDEX par_ind (parent_id)
, PRIMARY KEY (id)
, FOREIGN KEY (parent_id) REFERENCES parent(id)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=INNODB;
mysql>
INSERT INTO parent
VALUES (NULL), (NULL), (NULL), (NULL), (NULL), (NULL);
mysql>
SELECT * FROM parent;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
+----+
б. Сега трябва да изтрием някои от редовете, за да демонстрираме проблема:
mysql>
DELETE FROM parent WHERE id IN (3, 5);
в. ПРОБЛЕМ: Проблемът възниква, когато се опитате да вмъкнете следните дъщерни редове:
mysql>
INSERT IGNORE INTO child
VALUES
(NULL, 1)
, (NULL, 2)
, (NULL, 3)
, (NULL, 4)
, (NULL, 5)
, (NULL, 6);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint f
ails (`test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERE
NCES `parent` (`id`) ON DELETE CASCADE ON UPDATE CASCADE)
mysql>
SELECT * FROM child;
Empty set (0.00 sec)
Въпреки че IGNORE
се използва ключова дума, но MySQL отменя заявената операция, тъй като генерираната грешка не се превръща в предупреждение (както би трябвало). Сега, когато проблемът е очевиден, нека видим как можем да изпълним последното вмъкване в оператор, без да се сблъскаме с грешка.
г. РЕШЕНИЕ: Ще увия вмъкването в оператор с някои други константни оператори, които не зависят нито от вмъкнатите записи, нито от техния брой.
mysql>
SET FOREIGN_KEY_CHECKS = 0;
mysql>
INSERT INTO child
VALUES
(NULL, 1)
, (NULL, 2)
, (NULL, 3)
, (NULL, 4)
, (NULL, 5)
, (NULL, 6);
mysql>
DELETE FROM child WHERE parent_id NOT IN (SELECT id FROM parent);
mysql>
SET FOREIGN_KEY_CHECKS = 1;
Знам, че това не е оптимално, но докато MySQL не е отстранил проблема, това е най-доброто, което знам. Още повече, че всички оператори могат да бъдат изпълнени в една заявка, ако използвате mysqli библиотека в PHP.