15.2.12 Оператор REPLACE
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».
DELAYED вставки и замены были устаревшими в MySQL 5.6. В MySQL 9.2 DELAYED не поддерживается. Сервер распознает, но игнорирует ключевое слово DELAYED, обрабатывает замену как незадержанную замену и генерирует предупреждение: REPLACE DELAYED больше не поддерживается. Оператор был преобразован в REPLACE. Ключевое слово DELAYED запланировано к удалению в будущей версии.
REPLACE имеет смысл только в том случае, если таблица имеет PRIMARY KEY или UNIQUE индекс. В противном случае он становится эквивалентным INSERT, поскольку нет индекса, который можно было бы использовать для определения того, дублирует ли новая строка другую.
Значения для всех столбцов берутся из значений, указанных в операторе REPLACE. Любые отсутствующие столбцы устанавливаются в их значения по умолчанию, как и в случае с оператором INSERT. Вы не можете ссылаться на значения из текущей строки и использовать их в новой строке. Если вы используете присваивание, такое как SET
, ссылка на имя столбца в правой части обрабатывается как col_name =
col_name + 1DEFAULT(, поэтому присваивание эквивалентно col_name)SET
.col_name =
DEFAULT(col_name) + 1
Вы можете указать значения столбцов, которые REPLACE пытается вставить, используя оператор VALUES ROW().
Для использования оператора REPLACE необходимо иметь права INSERT и DELETE для таблицы.
Если сгенерированный столбец заменяется явно, единственное допустимое значение — DEFAULT. Сведения о сгенерированных столбцах см. в Разделе 15.1.21.8, «Оператор CREATE TABLE и сгенерированные столбцы».
REPLACE поддерживает явное выделение разделов с помощью предложения PARTITION с перечислением разделов, подразделов или того и другого через запятую. Как и в случае с INSERT, если невозможно вставить новую строку в любой из этих разделов или подразделов, оператор REPLACE завершается с ошибкой Найдена строка, не соответствующая заданному набору разделов. Более подробную информацию и примеры см. в Разделе 26.5, «Выбор разделов».
Оператор REPLACE возвращает количество, указывающее количество затронутых строк. Это сумма строк, которые были удалены и вставлены. Если количество равно 1 для оператора REPLACE с одной строкой, строка была вставлена, и никакие строки не были удалены. Если количество больше 1, одна или несколько старых строк были удалены перед вставкой новой строки. Возможно, что одна строка заменит более одной старой строки, если таблица содержит несколько уникальных индексов, и новая строка дублирует значения для разных старых строк в разных уникальных индексах.
Количество затронутых строк упрощает определение, добавил ли оператор REPLACE только строку или также заменил какие-либо строки: проверьте, равно ли количество 1 (добавлено) или больше (заменено).
При использовании API C количество затронутых строк можно получить, используя функцию.
Нельзя заменить таблицу и выбрать из той же таблицы в подзапросе.
MySQL использует следующий алгоритм для REPLACE (и LOAD DATA ...
REPLACE):
Попытаться вставить новую строку в таблицу
-
Пока вставка завершается неудачей из-за ошибки дублирования ключа для первичного ключа или уникального индекса:
Удалить из таблицы конфликтную строку, имеющую значение дублирующего ключа
Повторить попытку вставки новой строки в таблицу
Возможно, что в случае ошибки дублирования ключа движок хранения может выполнить REPLACE как обновление, а не удаление плюс вставку, но семантика остается такой же. Нет видимых пользователю эффектов, кроме возможной разницы в том, как движок хранения увеличивает Handler_ статусные переменные.xxx
Поскольку результаты операторов REPLACE ... SELECT зависят от порядка строк из SELECT, и этот порядок не всегда гарантируется, при протоколировании этих операторов для источника и реплики возможно расхождение. По этой причине операторы REPLACE ... SELECT помечаются как небезопасные для репликации на основе операторов. Такие операторы генерируют предупреждение в журнале ошибок при использовании режима на основе операторов и записываются в двоичный журнал с помощью формата на основе строк при использовании режима MIXED. См. также Раздел 19.2.1.1, «Преимущества и недостатки репликации на основе операторов и на основе строк».
MySQL 9.2 поддерживает 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 те же два REPLACE оператора, что и на исходной test таблице, мы получим другой результат:
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 должны совпадать со значениями существующей строки для замены строки; в противном случае строка вставляется.
© 2025 Oracle
Licensed under the GPLv2 License.