MySQL的INSERT IGNORE INTO和外键

Meh*_*ran 34 mysql ignore foreign-keys insert

为什么在MySQL中,INSERT IGNORE INTO不会将外键约束错误更改为警告?

我正在尝试将一些记录插入到表中,我希望MySQL省去导致错误,错误和插入其余错误的记录.有没有人有什么建议?

SET FOREIGN_KEY_CHECKS = 0;不是我的答案.因为我希望不会插入违反约束的行.

谢谢

Meh*_*ran 33

[新答案]

感谢@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                        |
+-------------------------+------------------------------+
Run Code Online (Sandbox Code Playgroud)

要明确:

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 |
+----+
Run Code Online (Sandbox Code Playgroud)

现在我们需要删除一些行来演示问题:

mysql>
DELETE FROM parent WHERE id IN (3, 5);
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

尽管使用了IGNORE关键字,但是MySQL取消了所请求的操作,因为生成的错误没有变成警告(正如它所预料的那样).现在问题很明显,让我们看看如何在不面临任何错误的情况下执行最后一次插入语句.

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;
Run Code Online (Sandbox Code Playgroud)

我知道这不是最佳的,但只要MySQL没有解决问题,这就是我所知道的最好的.特别是因为如果在PHP中使用mysqli库,所有语句都可以在一个请求中执行.

  • 从 MySQL 5.7.22 开始,我通过 INSERT IGNORE 得到了正确的行为。插入 4 行,生成 2 行警告。禁用 FOREIGN_KEY_CHECKS 会插入 6 行!这是你想要的吗? (2认同)

Dou*_*ess 6

我认为问题的最简单的mysql解决方案是加入外键表以验证约束:

INSERT INTO child (parent_id, value2, value3)
SELECT p.id, @new_value2, @new_value3
FROM parent p WHERE p.id = @parent_id
Run Code Online (Sandbox Code Playgroud)

但是你想要丢失基于丢失外键的记录似乎很奇怪.例如,我更喜欢在外键检查时出现INSERT IGNORE错误.