# 9.8 REPLACE 语句

在本教程中，您将学习如何使用MySQL `REPLACE`语句向数据库表插入或更新数据。

## MySQL REPLACE语句简介

MySQL `REPLACE`语句是标准SQL的MySQL扩展。 MySQL `REPLACE`语句的工作原理如下：

* 如果给定行数据不存在，那么MySQL REPLACE语句会[插入一个新行](http://www.yiibai.com/mysql/insert-statement.html)。
* 如果给定行数据存在，则`REPLACE`语句首先[删除](http://www.yiibai.com/mysql/delete-statement.html)旧行，然后[插入](http://www.yiibai.com/mysql/insert-statement.html)一个新行。 在某些情况下，`REPLACE`语句仅更新现有行。

MySQL使用[PRIMARY KEY](http://www.yiibai.com/mysql/primary-key.html)或`UNIQUE KEY`索引来要确定表中是否存在新行。如果表没有这些索引，则`REPLACE`语句等同于[INSERT语句](http://www.yiibai.com/mysql/insert-statement.html)。

要使用MySQL `REPLACE`语句，至少需要具有`INSERT`和`DELETE`权限。

> 请注意，有一个[REPLACE](http://www.yiibai.com/mysql/string-replace-function.html)字符串函数，它不是本教程中说述的`REPLACE`语句。

## MySQL REPLACE语句示例

我们来看一下使用`REPLACE`语句来更好地了解它的工作原理的例子。

首先，创建一个名为`cities`的新表，如下所示：

```sql
USE testdb;

CREATE TABLE cities (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50),
    population INT NOT NULL
);
```

接下来，在`cities`表中[插入](http://www.yiibai.com/mysql/insert-statement.html)一些行记录：

```sql
INSERT INTO cities(name,population)
VALUES('New York',8008278),
   ('Los Angeles',3694825),
   ('Shanghai',1923400);
```

下面查询`cities`表中的数据，以验证插入操作 -

```sql
mysql> SELECT * FROM cities;
+----+-------------+------------+
| id | name        | population |
+----+-------------+------------+
|  1 | New York    |    8008278 |
|  2 | Los Angeles |    3694825 |
|  3 | Shanghai    |    1923400 |
+----+-------------+------------+
3 rows in set
```

现在，在`cities`表中有三个城市数据。

那么，假设我们要将纽约市的人口更新为`1008256`，可以使用[UPDATE语句](http://www.yiibai.com/mysql/update-data.html)如下：

```sql
UPDATE cities 
SET 
    population = 1008256
WHERE
    id = 1;
```

再次查询`cities`表中的数据来验证更新结果 -

```sql
mysql> UPDATE cities 
SET 
    population = 1008256
WHERE
    id = 1;
Query OK, 1 row affected
Rows matched: 1  Changed: 1  Warnings: 0

mysql> SELECT * FROM cities;
+----+-------------+------------+
| id | name        | population |
+----+-------------+------------+
|  1 | New York    |    1008256 |
|  2 | Los Angeles |    3694825 |
|  3 | Shanghai    |    1923400 |
+----+-------------+------------+
3 rows in set
```

`UPDATE`语句的确按照预期更新了数据。

之后，使用`REPLACE`声明将洛杉矶市的人口更新为`3696820`。

```sql
REPLACE INTO cities(id,population) VALUES(2,3696820);
Query OK, 2 rows affected
```

上面执行返回结果中提示：*2 rows affected*，说明有两行数据受影响。

最后，再次查询城市表的数据来验证替换的结果。

```sql
mysql> SELECT  * FROM  cities;
+----+----------+------------+
| id | name     | population |
+----+----------+------------+
|  1 | New York |    1008256 |
|  2 | NULL     |    3696820 |
|  3 | Shanghai |    1923400 |
+----+----------+------------+
3 rows in set
```

现在`name`列为`NULL`。 您可能期望`name`列的值保持不变。但是，`REPLACE`语句不这样做。 在这种情况下，`REPLACE`语句的工作原理如下：

* `REPLACE`语句首先使用列列表提供的信息将新行插入到`cities`表中。但是插入失败，因为在`cities`表中已经存在`ID`为`2`的行记录，因此，MySQL引发了重复键错误。
* 然后，`REPLACE`语句更新具有`id`列值为`2`指定的行记录。在正常进程中，它将先删除具有冲突`id`为`2`的旧行，然后插入一个新行。

## MySQL REPLACE和INSERT

`REPLACE`语句的第一种形式类似于`INSERT`语句，除了`INSERT`关键字换成`REPLACE`关键字以外，如下所示：

```sql
REPLACE INTO table_name(column_list)
VALUES(value_list);
```

例如，如果要在`cities`表中插入新行，请使用以下查询：

```sql
REPLACE INTO cities(name,population)
VALUES('Phoenix',1321523);
```

请注意，没有出现在`REPLACE`语句中的列将使用默认值插入相应的列。 如果列具有`NOT NULL`属性并且没有默认值，并且您如果没有在`REPLACE`语句中指定该值，则MySQL将引发错误。这是`REPLACE`和`INSERT`语句之间的区别。

例如，在以下语句中，仅指定`name`列的值，而没有指定`population`列。MySQL引发错误消息。 因为`population`列不接受`NULL`值，而我们定义`cities`表时，也没有指定`population`列的默认值。

```sql
REPLACE INTO cities(name)
VALUES('Houston');
```

执行上面语句后，MySQL发出如下的错误消息：

```sql
Error Code: 1364. Field 'population' doesn't have a default value
```

## MySQL REPLACE和UPDATE

`REPLACE`语句的第二种形式类似于`UPDATE`语句，如下所示：

```sql
REPLACE INTO table
SET column1 = value1,
    column2 = value2;
```

请注意，`REPLACE`语句中没有[WHERE子句](http://www.yiibai.com/mysql/where.html)。

例如，如果要将`Phoenix`城市的人口更新为`1768980`，请使用`REPLACE`语句，如下所示：

```sql
REPLACE INTO cities
SET id = 4,
    name = 'Phoenix',
    population = 1768980;
```

与`UPDATE`语句不同，如果不在`SET`子句中指定列的值，则`REPLACE`语句将使用该列的默认值。

```sql
SELECT * FROM cities;
```

## MySQL REPLACE INTO和SELECT

`REPLACE`语句的第三种形式类似于[INSERT INTO SELECT](http://www.yiibai.com/mysql/insert-statement.html)语句：

```sql
REPLACE INTO table_1(column_list)
SELECT column_list
FROM table_2
WHERE where_condition;
```

假设要复制`ID`为`1`的城市行记录，可以使用`REPLACE INTO SELECT`语句，如下查询示例：

```sql
REPLACE INTO cities(name,population)
SELECT name,population FROM cities 
WHERE id = 1;
```

## MySQL REPLACE语句用法

使用`REPLACE`语句时需要知道几个重点：

* 如果您开发的应用程序不仅支持MySQL数据库，而且还支持其他关系数据库管理系统(RDBMS)，则应避免使用`REPLACE`语句，因为其他RDBMS可能不支持。代替的作法是在[事务](http://www.yiibai.com/mysql/transaction.html)中使用[DELETE](http://www.yiibai.com/mysql/delete-statement.html)和INSERT语句的组合。
* 如果在具有触发器的表中使用了`REPLACE`语句，并且发生了重复键错误的删除，则[触发器](http://www.yiibai.com/mysql/triggers.html)将按以下顺序触发：在删除前删除，删除之后，删除后，如果`REPLACE`语句删除当前 行并插入新行。 如果`REPLACE`语句更新当前行，则触发`BEFORE UPDATE`和`AFTER UPDATE`触发器。

在本教程中，您学习了不同形式的`REPLACE`语句来插入或更新表中的数据。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://hezhiqiang-book.gitbook.io/mysql/di-yi-zhang/index-8/replace-yu-ju.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
