重复密钥更新节点Mysql只更新唯一行

我正在使用MySQL 5.7节点JS 6.11.0,并试图更新一个UNIQUE MySQL列,每当我插入一个有冲突的行。 但是,当我尝试插入有冲突的logging时,只有现有的logging更新为NULL ,不会发生insert 。 这是我的代码

  pool.getConnection(function(err, connection) { var newClass = req.body; var query = `INSERT INTO classes SET ? ON DUPLICATE KEY UPDATE teacher_id = NULL`; connection.query(query, newClass, function(err, result) { console.log(result); if(result.affectedRows >= 1) { res.status(201).end(); res.json(result); } }); connection.release(); });` 

我必须运行查询两次要插入的行; 第一次冲突的列被设置为空,那么当我再次运行相同的查询时,行被插入,因为没有冲突。

我已经采取了生成的SQL,并直接从MySql控制台运行它,我仍然需要运行查询两次插入新行。 我不明白为什么这样做。

sql语句是

 INSERT INTO classes SET `stream` = 'Red', `form` = '1', `teacher_id` = '7' ON DUPLICATE KEY UPDATE teacher_id = NULL 

我的创build表SQL是

 | classes | CREATE TABLE `classes` ( `id` int(11) NOT NULL AUTO_INCREMENT, `form` varchar(10) NOT NULL, `stream` varchar(15) NOT NULL, `teacher_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `teacher_id` (`teacher_id`), CONSTRAINT `classes_ibfk_1` FOREIGN KEY (`teacher_id`) REFERENCES `teachers` ( `id` ) ) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=latin1 |` 

为什么MySQL这样做?

 INSERT INTO classes SET stream = 'Red', form = '1',teacher_id = '7' ON DUPLICATE KEY UPDATE teacher_id = NULL; 

当有冲突的logging(重复的唯一或主键)时告诉MySQL,将有问题的行的teacher_id列设置为null并停止。

你有几个选项来实现你想要的结果。

首先,您可以使用REPLACE语法。

 REPLACE INTO classes SET stream = 'Red', form = '1', teacher_id = '7'; 

它将首先删除具有UNIQUE或Primary Key约束的有问题的行,然后插入一个具有指定值的新行。 缺点是任何省略的列值将丢失并设置为其默认值。 如果在查询中没有指定,也会创build一个新的自动生成的(如果有的话)ID。 如果没有违规logging,则会发生正常的INSERT

否则,可以在UPDATE子句中使用VALUES

 INSERT INTO classes SET stream = 'Red', form = '1', teacher_id = '7' ON DUPLICATE KEY UPDATE stream = VALUES(stream), form = VALUES(form); 

相反,这会将违规行的logging更新为在查询的INSERT部分中指定的值。

参考文献:


根据新的意图更新

为了在离开前一行时创build一条新logging,在使用INSERT之前,需要首先使现有行上的UNIQUE约束无效。 目前还没有一种方法可以在单个查询中使用MySQL。

由于INSERT限制,最简单的方法是在INSERT查询之前运行UPDATE查询。

 UPDATE classes SET teacher_id = NULL WHERE teacher_id = '7'; INSERT INTO classes SET stream = 'Red', form = '1', teacher_id = '7'; 

这将首先检查冲突的teacher_idlogging并将其设置为null 。 如果没有冲突logging,则不会发生更新。 接下来的INSERT会创build所需的logging,而不会发生冲突。

如果你想根据条件插入数据试试这个

 INSERT INTO table1 SELECT 'Red',1,7 FROM table2 where teacher_id IS NULL; 

否则如果你想更新的基础上尝试这一点。

 update table1 SET stream = 'Red', form = '1', teacher_id = '7' where teacher_id IS NULL; 

注意:NULL = NULL不是真的 – 它又是NULL。 但是它也不是真的,所以IF(NULL = NULL)将不会执行。例如,即使对NULL本身,NULL也会testingFALSE。 所以,使用NULL只能用上述函数(和IS NULL())来完成。 您的查询可以重写为上面。