mysql 存在更新 不存在插入

本文介绍MySQL自4.1版起支持的INSERT...ON DUPLICATE KEY UPDATE语法,通过实例展示了如何利用这一特性减少代码量,提高效率。特别是对于含有大量重复数据的场景,如日志统计等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

看程序竟然发现Mysql有这个功能!

今天写程序,新发现……………………,相当不错^_^,省略了很多功夫,每天1G多的日志!!

MySQL 自4.1版以后开始支持INSERT … ON DUPLICATE KEY UPDATE语法,使得原本需要执行3条SQL语句(SELECT,INSERT,UPDATE),缩减为1条语句即可完成。

INSERT ... ON DUPLICATE KEY UPDATE,当插入的记录会引发主键冲突或者违反唯一约束时,则使用UPDATE更新旧的记录,否则插入新记录。

例如ipstats表结构如下:

CREATE TABLE ipstats (ip VARCHAR(15) NOT NULL UNIQUE,clicks SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0');

原本需要执行3条SQL语句,如下:

IF (SELECT * FROM ipstats WHERE ip='192.168.0.1') {    UPDATE ipstats SET clicks=clicks+1 WHERE ip='192.168.0.1';} else {    INSERT INTO ipstats (ip, clicks) VALUES ('192.168.0.1', 1);}

而现在只需下面1条SQL语句即可完成:

INSERT INTO ipstats VALUES('192.168.0.1', 1) ON DUPLICATE KEY UPDATE clicks=clicks+1;

注意,要使用这条语句,前提条件是这个表必须有一个唯一索引或主键。

再看一例子:
mysql> desc test;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| uid   | int(11)     | NO   | PRI |         |       |
| uname | varchar(20) | YES |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql> select * from test;
+-----+--------+
| uid | uname |
+-----+--------+
|   1 | uname1 |
|   2 | uname2 |
|   3 | me     |
+-----+--------+
3 rows in set (0.00 sec)

mysql> INSERT INTO test values ( 3,'insertName' )
    -> ON DUPLICATE KEY UPDATE uname='updateName';
Query OK, 2 rows affected (0.03 sec)

mysql> select * from test;
+-----+------------+
| uid | uname      |
+-----+------------+
|   1 | uname1     |
|   2 | uname2     |
|   3 | updateName |
+-----+------------+
3 rows in set (0.00 sec)

mysql> create index i_test_uname on test(uname);
Query OK, 3 rows affected (0.20 sec)
Records: 3 Duplicates: 0 Warnings: 0

mysql> INSERT INTO test VALUES ( 1 , 'uname2')   
-> ON DUPLICATE KEY UPDATE uname='update2records';
Query OK, 2 rows affected (0.00 sec)

mysql> select * from test;
+-----+----------------+
| uid | uname          |
+-----+----------------+
|   2 | uname2         |
|   1 | update2records |
|   3 | updateName     |
+-----+----------------+
3 rows in set (0.00 sec)

插入时会与两条记录发生冲突,分别由主键和唯一索引引起。但最终只UPDATE了其中一条。这在手册中也说明了,有多个唯一索引(或者有键也有唯一索引)的情况下,不建议使用该语句。

create table xx (sad,xasd,asda,primary key(a,x,a));就可以用了,注意一定要有由主键和唯一索引^_^

转载于:https://www.cnblogs.com/sunss/archive/2010/10/05/1844208.html

<think>我们正在讨论MySQL中的"upsert"操作(存在更新存在插入)。根据引用内容,有两种主要方法:`REPLACE INTO`和`INSERT ... ON DUPLICATE KEY UPDATE`(推荐使用后者)。 引用[1]指出:`REPLACE INTO`会先删除旧记录再插入新记录,这可能导致性能问题(尤其是当表有外键或触发器时)。而`INSERT ... ON DUPLICATE KEY UPDATE`则是在主键或唯一索引冲突时执行更新操作,会删除原记录,因此更高效。 引用[2]和[3]进一步说明了`ON DUPLICATE KEY UPDATE`的用法,特别是批量操作时,以及如何更新字段(例如自增字段)。 因此,推荐使用`INSERT ... ON DUPLICATE KEY UPDATE`语法。 步骤: 1. 确保表中存在主键或唯一索引(UNIQUE KEY),因为该操作依赖这些来判断是否重复。 2. 编INSERT语句,并在后面添加`ON DUPLICATE KEY UPDATE`子句,指定当冲突时需要更新的字段。 示例: 假设有一个表`users`,有字段`id`(主键),`name`,`email`(唯一索引),`age`。 我们想要插入一条记录,如果`email`冲突(即已存在相同的email),则更新该记录的`name`和`age`。 SQL语句如下: ```sql INSERT INTO users (id, name, email, age) VALUES (1, 'John', 'john@example.com', 30) ON DUPLICATE KEY UPDATE name = VALUES(name), age = VALUES(age); ``` 注意: - 这里通过唯一索引`email`判断重复(因为主键id也可能冲突,但这里我们假设id是自增的,通常会在插入时指定,或者指定了也可能冲突)。 - 在`ON DUPLICATE KEY UPDATE`子句中,我们使用`VALUES(column_name)`来引用INSERT语句中准备插入的值。 - 也可以直接指定值,例如:`name = 'John'`,但使用`VALUES(name)`可以确保使用INSERT中提供的值。 另一种情况:如果冲突时需要更新多个字段,可以全部列出。另外,如果只想更新部分字段,也可以只那些需要更新的字段。 批量操作: 引用[2]提到,该语法也支持批量插入更新。例如: ```sql INSERT INTO users (id, name, email, age) VALUES (1, 'John', 'john@example.com', 30), (2, 'Jane', 'jane@example.com', 25) ON DUPLICATE KEY UPDATE name = VALUES(name), age = VALUES(age); ``` 性能: 引用[3]给出了一个使用该语句进行计数字段自增的例子,说明这种操作是原子性的,适合计数场景。 因此,总结如下: - 使用`INSERT ... ON DUPLICATE KEY UPDATE`实现upsert操作。 - 需要确保有唯一性约束(主键或唯一索引)。 - 在更新部分,可以使用`VALUES(column_name)`来引用插入值。 注意:`REPLACE INTO`虽然也可以实现,但因为它会先删除再插入,可能导致自增主键改变(比如自增ID会变),并且会触发必要的删除和插入操作,影响性能,所以推荐。 相关问题: 1. 如何为表添加唯一索引以确保upsert操作正确执行? 2. 在`ON DUPLICATE KEY UPDATE`子句中,如何更新为特定值而插入的值? 3. 使用upsert操作时,如何避免自增主键的无谓增长? 4. 批量upsert操作时需要注意什么?</think>### MySQL Upsert操作详解 在MySQL中实现"存在更新存在插入"的操作称为**Upsert**。根据您提供的引用信息,推荐使用`INSERT ... ON DUPLICATE KEY UPDATE`语法,这是最高效的实现方式。 #### 核心语法 ```sql INSERT INTO 表名 (字段1, 字段2, ...) VALUES (值1, 值2, ...) ON DUPLICATE KEY UPDATE 字段1 = 新值1, 字段2 = 新值2; ``` #### 实现步骤 1. **确保存在唯一约束**(必备条件): - 主键(PRIMARY KEY) - 唯一索引(UNIQUE INDEX) - 组合唯一约束 ```sql ALTER TABLE 表名 ADD UNIQUE INDEX idx_unique (字段1, 字段2); ``` 2. **执行Upsert操作**: ```sql -- 示例:用户表存在更新积分,存在插入 INSERT INTO users (id, name, score) VALUES (101, '张三', 100) ON DUPLICATE KEY UPDATE score = VALUES(score) + 10; -- 冲突时积分+10 ``` 3. **批量操作**(高效方式): ```sql INSERT INTO products (sku, stock) VALUES ('P1001', 50), ('P1002', 30), ('P1003', 20) ON DUPLICATE KEY UPDATE stock = VALUES(stock); ``` #### 性能对比 | 方法 | 特点 | 性能 | |-------------------------------|----------------------------------------------------------------------|--------| | `ON DUPLICATE KEY UPDATE` | 直接更新记录,删除原有数据 | ★★★★★ | | `REPLACE INTO` | 先删除旧记录再插入新数据,触发级联删除 | ★★☆☆☆ | | 先查询再选择插入/更新 | 需要两次数据库交互 | ★☆☆☆☆ | #### 使用技巧 1. **引用插入值**: `VALUES(字段名)`获取插入语句中的值 ```sql ON DUPLICATE KEY UPDATE views = views + VALUES(views) ``` 2. **条件更新**: ```sql ON DUPLICATE KEY UPDATE price = IF(VALUES(price) > 0, VALUES(price), price) ``` 3. **自增字段处理**: 使用`LAST_INSERT_ID()`避免自增ID跳跃 ```sql INSERT ... ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id) ``` #### 注意事项 1. 必须存在唯一约束,否则会变成纯插入操作 2. 更新时会触发`BEFORE UPDATE`触发器 3. 返回结果: - 新插入:返回`1`(受影响行数) - 更新:返回`2`(删除旧行+插入新行计数) 4. 在高并发场景建议使用事务 > 示例:计数器场景[^3] > ```sql > INSERT INTO page_views (page_id, date, views) > VALUES (123, CURDATE(), 1) > ON DUPLICATE KEY UPDATE views = views + 1; > ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值