How do I update if exists, insert if not (AKA “upsert” or “merge”) in MySQL?
是否有一个简单的方法INSERT一行不存在时,或UPDATE如果它存在,使用一个MySQL查询?
是的,INSERT ... ON DUPLICATE KEY UPDATE。例如:
1 2 3 4 5 6
| INSERT INTO `usage`
(`thing_id`, `times_used`, `first_time_used`)
VALUES
(4815162342, 1, NOW())
ON DUPLICATE KEY UPDATE
`times_used` = `times_used` + 1 |
-
哇,太棒了。其他RDMS是否有此功能?
-
是的,我相信SQL Server的等价物被称为MERGE。通常,该概念通常被称为"UPSERT"。
-
但是当没有prim.key存在时,这不起作用。我的表看起来像这样:geb |主题|访问我想插入INSERT INTO表SET visited = NOW(),geb = 1,topic = 1但是如果已经有geb = 1&&的组合topic = 1然后它应该更新行而不是插入新行。
-
在GEB和主题上制作一个独特的索引
-
@blub:如果你在geb和topic上创建一个唯一键,它将起作用(ALTER TABLE table ADD UNIQUE geb_by_topic (geb, topic))。
-
我没有输入prim.key,因为我不得不使用新列,因为geb和topic都不是唯一的。我不知道有可能把钥匙配对两列! Thanx混乱。
-
@Brian:Oracle的等价物也称为MERGE,但我不确定它的语法是否与SQL Server相同。
-
@iAn:事实并非如此。如果使用SELECT检查是否存在,则执行INSERT,如果使用ON DUPLICATE KEY UPDATE,则会出现不存在的并发问题。
-
由于时间on duplicate被击中,这个代码性能是否良好?有更好的解决方案吗?
-
@Yasser Souri:它变得如此美好。
-
我把'thing_id'设置为autoincrement(并且是主键)并将它传递给'0',结果将是'thing_id'的下一个值的插入?
-
@Brooks:如果你传递0,它实际上会使用0作为值。所以不要这样做。不要传递任何东西,或传递NULL,以允许auto_increment行为工作(否则,是的,按照您的假设工作;请参阅dev.mysql.com/doc/refman/5.5/en/例如,自动increment.html)。
-
如果有多个唯一索引,您如何做到这一点?我只想更新记录,如果已经存在的记录有2个相同的属性,而不是一个或另一个。
-
@CMCDragonkai:机制的ON DUPLICATE KEY部分意味着如果INSERT尝试在唯一键中生成重复,它只会转到UPDATE。如果在您的情况下不会发生这种情况,那么您无法使用此机制来解决它。
-
对于那些想知道的人,这个例子将为发现的重复行更新times_used。
-
我已经在使用这个了,我想扩展这个问题。有没有办法从这种方法中获得受影响(更新/插入)的ID
-
@Ruwantha:文档中包含了执行此操作的示例:dev.mysql.com/doc/refman/5.1/en/insert-on-duplicate.html
-
@chaos:非常有帮助,在我的情况下,id不是增量的。我想没有解决方案。
-
谢谢,如果重复,可以使用VALUES(col)从insert参数中获取值。例如:ON DUPLICATE UPDATE b = VALUES(b), c = VALUES(c)
-
@chaos和其他人,我想使用这个查询,但我想检查是否存在针对project_id = pId和expert_id = eId的记录,然后UPDATE ml_match否则INSERT project_id,expert_id,ml_match并忽略其他列。你能写查询吗? ON DUPLICATE KEY UPDATE仅适用于主键或任何字段名称吗?
-
@KhalidUsman:你应该写一个问题,而不是评论。
我知道这是一个老问题,但Google最近引导我到这里,所以我想其他人也来到这里。
@chaos是正确的:有INSERT ... ON DUPLICATE KEY UPDATE语法。
但是,最初的问题是专门询问MySQL,而在MySQL中则有REPLACE INTO ...语法。恕我直言,这个命令更容易,更直接用于upserts。从手册:
REPLACE works exactly like INSERT, except that if an old row in the table has the same value as a new row for a PRIMARY KEY or a UNIQUE index, the old row is deleted before the new row is inserted.
请注意,这不是标准SQL。手册中的一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| CREATE TABLE test (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
DATA VARCHAR(64) DEFAULT NULL,
ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
mysql> REPLACE INTO test VALUES (1, 'Old', '2014-08-20 18:47:00');
Query OK, 1 ROW affected (0.04 sec)
mysql> REPLACE INTO test VALUES (1, 'New', '2014-08-20 18:47:42');
Query OK, 2 ROWS affected (0.04 sec)
mysql> SELECT * FROM test;
+----+------+---------------------+
| id | DATA | ts |
+----+------+---------------------+
| 1 | NEW | 2014-08-20 18:47:42 |
+----+------+---------------------+
1 ROW IN SET (0.00 sec) |
编辑:只是一个公平的警告REPLACE INTO不像UPDATE。如手册所述,REPLACE删除该行(如果存在),然后插入一个新行。 (请注意上面示例中有趣的"2行受影响"。)也就是说,它将替换现有记录的所有列的值(而不仅仅是更新某些列。)MySQL的REPLACE INTO的行为非常类似于Sqlite的INSERT OR REPLACE INTO。如果您只想更新一些列(而不是所有列),如果该记录已存在,请参阅此问题以获取一些解决方法。