REPLACE [LOW_PRIORITY | DELAYED]
[INTO] tbl_name
[PARTITION (partition_name [, partition_name] ...)]
[(col_name [, col_name] ...)]
{ {VALUES | VALUE} (value_list) [, (value_list)] ...
|
VALUES row_constructor_list
}
REPLACE [LOW_PRIORITY | DELAYED]
[INTO] tbl_name
[PARTITION (partition_name [, partition_name] ...)]
SET assignment_list
REPLACE [LOW_PRIORITY | DELAYED]
[INTO] tbl_name
[PARTITION (partition_name [, partition_name] ...)]
[(col_name [, col_name] ...)]
{SELECT ... | TABLE table_name}
value:
{expr | DEFAULT}
value_list:
value [, value] ...
row_constructor_list:
ROW(value_list)[, ROW(value_list)][, ...]
assignment:
col_name = value
assignment_list:
assignment [, assignment] ...
REPLACE 的工作原理与 INSERT 完全相同,不同之处在于,如果表中已有行的 PRIMARY KEY 或 UNIQUE 索引值与新行的值相同,则在插入新行之前会先删除旧行。请参见 第 15.2.7 节,“INSERT 语句”。
REPLACE 是 MySQL 对 SQL 标准的扩展。它要么插入,要么 删除 并插入。有关另一个 MySQL 对 SQL 标准的扩展(要么插入,要么 更新),请参见 第 15.2.7.2 节,“INSERT ... ON DUPLICATE KEY UPDATE 语句”。
MySQL 5.6 中已弃用 DELAYED 插入和替换。在 MySQL 8.4 中,不支持 DELAYED。服务器识别但不处理 DELAYED 关键字,将替换处理为非延迟替换,并生成一个 ER_WARN_LEGACY_SYNTAX_CONVERTED 警告:不再支持 REPLACE DELAYED。语句已转换为 REPLACE。计划在将来的版本中删除 DELAYED 关键字。
所有列的值都取自 REPLACE 语句中指定的值。任何缺失的列都将设置为其默认值,就像 INSERT 一样。您不能引用当前行中的值并在新行中使用它们。如果您使用诸如 SET 之类的赋值,则等号右侧的列名引用将被视为 col_name = col_name + 1DEFAULT(,因此赋值等同于 col_name)SET 。col_name = DEFAULT(col_name) + 1
您可以使用 VALUES ROW() 指定 REPLACE 尝试插入的列值。
要使用 REPLACE,您必须同时拥有该表的 INSERT 和 DELETE 权限。
如果显式替换生成的列,则唯一允许的值是 DEFAULT。有关生成列的信息,请参见 第 15.1.20.8 节,“CREATE TABLE 和生成列”。
REPLACE 支持使用带有逗号分隔的分区、子分区或两者的名称列表的 PARTITION 子句进行显式分区选择。与 INSERT 一样,如果无法将新行插入到这些分区或子分区中的任何一个,则 REPLACE 语句将失败并出现错误 Found a row not matching the given partition set。有关更多信息和示例,请参见 第 26.5 节,“分区选择”。
REPLACE 语句返回一个计数以指示受影响的行数。这是删除和插入的行数的总和。如果对于单行 REPLACE 计数为 1,则插入了一行,没有删除任何行。如果计数大于 1,则在插入新行之前删除了一行或多行。如果表包含多个唯一索引,并且新行在不同的唯一索引中重复了不同旧行的值,则单个行可能会替换多个旧行。
受影响的行计数使您可以轻松确定 REPLACE 是否只添加了一行,或者它是否还替换了任何行:检查计数是否为 1(已添加)或更大(已替换)。
如果您使用的是 C API,则可以使用 mysql_affected_rows() 函数获取受影响的行计数。
您不能在子查询中替换表并从同一表中选择数据。
MySQL 对 REPLACE(以及 LOAD DATA ... REPLACE)使用以下算法
尝试将新行插入表中
当插入失败是因为主键或唯一索引出现重复键错误时
从表中删除具有重复键值的冲突行
再次尝试将新行插入表中
在出现重复键错误的情况下,存储引擎可能会将 REPLACE 作为更新执行,而不是删除加插入,但语义相同。除了存储引擎可能如何递增 Handler_ 状态变量之外,没有用户可见的影响。xxx
由于 REPLACE ... SELECT 语句的结果取决于 SELECT 中行的顺序,并且无法始终保证此顺序,因此在记录源和副本的这些语句时,它们可能会发生分歧。出于这个原因,REPLACE ... SELECT 语句被标记为不适合基于语句的复制。使用基于语句的模式时,此类语句会在错误日志中生成警告,并在使用 MIXED 模式时使用基于行的格式写入二进制日志。另请参见 第 19.2.1.1 节,“基于语句的复制和基于行的复制的优缺点”。
MySQL 8.4 支持 TABLE 以及 SELECT 与 REPLACE 一起使用,就像它与 INSERT 一起使用一样。有关更多信息和示例,请参见 第 15.2.7.1 节,“INSERT ... SELECT 语句”。
当修改现有的非分区表以适应分区时,或者当修改已分区表的划分时,您可能需要考虑更改表的 主键(请参见 第 26.6.1 节,“分区键、主键和唯一键”)。您应该意识到,如果您这样做,REPLACE 语句的结果可能会受到影响,就像您修改了非分区表的 主键一样。考虑以下 CREATE TABLE 语句创建的表
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 客户端中运行所示的语句时,结果如下
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)现在我们创建一个与第一个几乎相同的第二个表,除了主键现在覆盖了 2 列,如下所示(强调的文本)
CREATE TABLE test2 (
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, ts)
);当我们在 test2 上运行与我们在原始 test 表上运行的两个 REPLACE 语句相同的两个 REPLACE 语句时,我们得到了不同的结果
mysql> REPLACE INTO test2 VALUES (1, 'Old', '2014-08-20 18:47:00');
Query OK, 1 row affected (0.05 sec)
mysql> REPLACE INTO test2 VALUES (1, 'New', '2014-08-20 18:47:42');
Query OK, 1 row affected (0.06 sec)
mysql> SELECT * FROM test2;
+----+------+---------------------+
| id | data | ts |
+----+------+---------------------+
| 1 | Old | 2014-08-20 18:47:00 |
| 1 | New | 2014-08-20 18:47:42 |
+----+------+---------------------+
2 rows in set (0.00 sec)这是因为,当在 test2 上运行时,id 和 ts 列值都必须与现有行的值匹配,才能替换该行;否则,将插入一行。