重复密钥更新节点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
部分中指定的值。
参考文献:
- https://dev.mysql.com/doc/refman/5.7/en/replace.html
- https://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html
根据新的意图更新
为了在离开前一行时创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_id
logging并将其设置为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())来完成。 您的查询可以重写为上面。