如何在MySQL中实现upsert:如果不存在则插入?

目录

1 使用 REPLACE

2 使用 INSERT ... ON DUPLICATE KEY UPDATE


使用 INSERT IGNORE 有效会导致 MySQL 在尝试执行语句时忽略执行错误 INSERT 。这意味着 包含 索引或  字段 INSERT IGNORE 中重复值的语句 不会 产生错误,而只是完全忽略该特定 命令。其明显目的是 针对数据库中已存在的数据以及进入系统的新数据的组合 执行大量语句。

例如,我们的 books 表可能已经包含一些记录:

mysql> SELECT * FROM books LIMIT 3;
+----+-------------------------+---------------------+----------------+
| id | title                   | author              | year_published |
+----+-------------------------+---------------------+----------------+
|  1 | In Search of Lost Time  | Marcel Proust       |           1913 |
|  2 | Ulysses                 | James Joyce         |           1922 |
|  3 | Don Quixote             | Miguel de Cervantes |           1605 |
+----+-------------------------+---------------------+----------------+
3 rows in set (0.00 sec)

如果我们有大量新数据和现有数据, INSERT 并且其中一部分数据包含字段的匹配值 id ( UNIQUE PRIMARY_KEY 表中的),则使用基本方法 INSERT 将产生预期的错误:

mysql> INSERT INTO books
    (id, title, author, year_published)
VALUES
    (1, 'Green Eggs and Ham''Dr. Seuss', 1960);
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'

另一方面,如果我们使用 INSERT IGNORE,则重复尝试将被忽略,并且不会发生任何错误:

mysql> INSERT IGNORE INTO books
    (id, title, author, year_published)
VALUES
    (1, 'Green Eggs and Ham''Dr. Seuss', 1960);
Query OK, 0 rows affected (0.00 sec)

1 使用 REPLACE


如果您希望实际替换 由于重复 或  如上所述的值而 INSERT 导致命令产生错误的行 ,则一种选择是选择该 语句。UNIQUEPRIMARY KEYREPLACE

当发出 REPLACE 语句时,每个发出的命令都有两种可能的结果:

  • 未找到具有匹配值的现有数据行,因此 INSERT 执行标准语句。
  • 找到匹配的数据行,导致使用标准语句删除该现有行 ,然后 执行DELETE 正常操作 。INSERT

例如,我们可以使用  苏斯博士的《绿鸡蛋和火腿》REPLACE 替换掉  马塞尔·普鲁斯特的《 id = 1 追忆似水年华》的现有记录:

mysql> REPLACE INTO books
    (id, title, author, year_published)
VALUES
    (1, 'Green Eggs and Ham''Dr. Seuss', 1960);
Query OK, 2 rows affected (0.00 sec)

请注意,尽管我们只改变了一行,但结果表明有  行受到了影响,因为我们实际上是 DELETED 用现有行 INSERTED 来替换它。

有关使用的更多信息, REPLACE 请参阅 官方文档

2 使用 INSERT ... ON DUPLICATE KEY UPDATE


 对于可能包含重复或 值的INSERTING 行, 替代的(通常是首选的)方法  是使用  语句和子句。UNIQUEPRIMARY KEYINSERT ... ON DUPLICATE KEY UPDATE

与 REPLACE - 由于 DELETE 它在必要时执行的命令而具有固有的破坏性命令 - 使用 INSERT ... ON DUPLICATE KEY UPDATE 是非破坏性的,因为它只会发出 INSERT 或 UPDATE 语句,但绝不会 DELETE

例如,我们决定替换 “绿鸡蛋和火腿”id = 1 的记录  ,并将其恢复为原始的“ 追忆似水年华” 记录。因此,我们可以采用原始  语句并添加新  子句:INSERTON DUPLICATE KEY UPDATE

mysql> SET @id = 1,
    @title = 'In Search of Lost Time',
    @author = 'Marcel Proust',
    @year_published = 1913;
INSERT INTO books
    (id, title, author, year_published)
VALUES
    (@id@title@author@year_published)
ON DUPLICATE KEY UPDATE
    title = @title,
    author = @author,
    year_published = @year_published;

请注意,我们使用了正常 UPDATE 语法(但不包括不必要的 table 名称和 SET 关键字),并且只分配值 non-UNIQUE 。此外,尽管该方法不需要它们 ON DUPLICATE KEY UPDATE 才能正常运行,但我们也选择使用它们, user variables 这样我们就不需要  多次指定我们想要的INSERT 实际 值。UPDATE

结果,我们的 id = 1 记录正如 UPDATED 预期的那样:

mysql> SELECT * FROM books LIMIT 1;
+----+------------------------+---------------+----------------+
| id | title                  | author        | year_published |
+----+------------------------+---------------+----------------+
|  1 | In Search of Lost Time | Marcel Proust |           1913 |
+----+------------------------+---------------+----------------+
1 row in set (0.00 sec)
  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在Spark,可以通过JDBC连接MySQL数据库并使用`upsert`语句来执行插入或更新操作。具体实现如下: 1. 导入必要的依赖: ```xml <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.23</version> </dependency> ``` 2. 创建一个`DataFrame`,并指定`DataFrame`的schema。假设需要将数据插入到名为`users`的MySQL,表结构如下: ```sql CREATE TABLE users ( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(100), age INT, PRIMARY KEY (id) ); ``` 则可以定义如下的schema: ```scala import org.apache.spark.sql.types._ val schema = StructType(Seq( StructField("name", StringType), StructField("age", IntegerType) )) ``` 3. 读取数据并将其转换为`DataFrame`: ```scala val rdd = sc.parallelize(Seq( ("Alice", 25), ("Bob", 30), ("Charlie", 35) )) val df = spark.createDataFrame(rdd).toDF("name", "age") ``` 4. 将`DataFrame`写入到MySQL: ```scala val url = "jdbc:mysql://localhost:3306/mydb" val user = "username" val password = "password" df.write .format("jdbc") .option("url", url) .option("dbtable", "users") .option("user", user) .option("password", password) .option("driver", "com.mysql.jdbc.Driver") .option("rewriteBatchedStatements", "true") .option("batchsize", "10000") .mode("append") .save() ``` 在上述代码,`url`用于指定MySQL数据库的连接地址,`user`和`password`用于指定数据库的用户名和密码,`dbtable`用于指定要写入的表名,`driver`用于指定MySQL的JDBC驱动程序。 `rewriteBatchedStatements`和`batchsize`用于优化写入性能。`rewriteBatchedStatements`设置为`true`时,表示使用批量写入模式,可以提高写入性能。`batchsize`用于指定每批次写入的记录数。 5. 如果需要执行`upsert`操作,则可以使用MySQL的`REPLACE INTO`语句或`ON DUPLICATE KEY UPDATE`语句。例如,如果需要根据`name`字段更新记录,则可以使用如下的SQL语句: ```sql INSERT INTO users (name, age) VALUES (?, ?) ON DUPLICATE KEY UPDATE age=VALUES(age) ``` 在Spark,可以通过以下方式执行`upsert`操作: ```scala df.write .format("jdbc") .option("url", url) .option("dbtable", "users") .option("user", user) .option("password", password) .option("driver", "com.mysql.jdbc.Driver") .option("rewriteBatchedStatements", "true") .option("batchsize", "10000") .option("rewriteBatchedStatements", "true") .option("rewriteBatchedStatements", "true") .option("rewriteBatchedStatements", "true") .option("rewriteBatchedStatements", "true") .option("rewriteBatchedStatements", "true") .option("rewriteBatchedStatements", "true") .option("rewriteBatchedStatements", "true") .option("rewriteBatchedStatements", "true") .option("rewriteBatchedStatements", "true") .option("rewriteBatchedStatements", "true") .option("rewriteBatchedStatements", "true") .option("rewriteBatchedStatements", "true") .option("rewriteBatchedStatements", "true") .option("rewriteBatchedStatements", "true") .option("rewriteBatchedStatements", "true") .option("rewriteBatchedStatements", "true") .option("rewriteBatchedStatements", "true") .option("rewriteBatchedStatements", "true") .mode("append") .jdbc(url, "users", prop) ``` 在上述代码,`prop`是一个包含`user`和`password`属性的`java.util.Properties`对象。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chat2tomorrow

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值