为什么在 MySQL 中,INSERT IGNORE INTO
不会将 外键约束 错误变为警告?
我正在尝试将一些记录插入到一个表中,我希望 MySQL 会忽略那些导致错误的记录,任何错误,然后插入其余的记录。有人有什么建议吗?
SET FOREIGN_KEY_CHECKS = 0;
不是我的答案。因为我希望根本不插入违反约束的行。
谢谢
最佳答案
[新答案]
感谢@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
To better understand the meaning of this last query and why it shows the problem is fixed, please continue with the old answer below.
[OLD ANSWER]
My solution is a work around to the problem and the actual solution will always be fixing the problem within the MySQL itself.
The following steps solved my problem:
a. Consider having the following tables and data:
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 |
+----+
b.现在我们需要删除一些行来演示问题:
mysql>
DELETE FROM parent WHERE id IN (3, 5);
c.问题: 当您尝试插入以下子行时会出现问题:
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 取消了请求的操作,因为生成的错误没有变成警告(如它应该的那样)。现在问题已经很明显了,让我们看看如何执行最后一个 insert into 语句而不会遇到任何错误。
d.解决方案:我将通过其他一些既不依赖于插入的记录也不依赖于它们的数量的常量语句将插入语句包装起来。
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 没有解决问题,这是我所知道的最好的。特别是如果你在 PHP 中使用 mysqli 库,所有语句都可以在一个请求中执行。
关于MySQL 的 INSERT IGNORE INTO & 外键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6849393/