При выполнении оператора INSERT
со многими строками я хочу пропустить повторяющиеся записи, которые в противном случае могли бы вызвать сбой. После некоторых исследований моими вариантами, по-видимому, являются либо:
ON DUPLICATE KEY UPDATE
, что подразумевает ненужное обновление при некоторой стоимости, либо INSERT IGNORE
, что подразумевает приглашение на другие виды неспособности проскользнуть без предупреждения. Прав ли я в этих предположениях? Как лучше всего пропустить строки, которые могут вызвать дублирование, и просто перейти к другим строкам?
Я рекомендовал бы использовать INSERT...ON DUPLICATE KEY UPDATE
.
, Если Вы используете INSERT IGNORE
, затем строка не будет на самом деле вставлена, если она приведет к дублирующемуся ключу. Но оператор не генерирует ошибку. Это генерирует предупреждение вместо этого. Эти случаи включают:
PRIMARY KEY
или UNIQUE
ограничения. NOT NULL
ограничение. , Если Вы используете REPLACE
, MySQL на самом деле делает DELETE
сопровождаемый INSERT
внутренне, который имеет некоторые неожиданные побочные эффекты:
REPLACE
. DELETE
, выполняются излишне. исправление: и REPLACE
и INSERT...ON DUPLICATE KEY UPDATE
нестандартные, собственные изобретения, характерные для MySQL. 2003 ANSI SQL определяет MERGE
оператор, который может решить ту же потребность (и больше), но MySQL не поддерживает MERGE
оператор.
пользователь А пытался отредактировать это сообщение (редактирование было отклонено модераторами). Редактирование пыталось добавить заявление что INSERT...ON DUPLICATE KEY UPDATE
причины новый автоинкрементный идентификатор, который будет выделен. Это верно, что новый идентификатор , генерировал , но это не используется в измененной строке.
Посмотрите демонстрацию ниже, протестированный с Сервером Percona 5.5.28. Переменная конфигурации innodb_autoinc_lock_mode=1
(значение по умолчанию):
mysql> create table foo (id serial primary key, u int, unique key (u));
mysql> insert into foo (u) values (10);
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 1 | 10 |
+----+------+
mysql> show create table foo\G
CREATE TABLE `foo` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`u` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u` (`u`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
mysql> insert into foo (u) values (10) on duplicate key update u = 20;
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 1 | 20 |
+----+------+
mysql> show create table foo\G
CREATE TABLE `foo` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`u` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u` (`u`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
Вышеупомянутое демонстрирует, что оператор IODKU обнаруживает дубликат и вызывает обновление для изменения значения [1 118]. Отметьте эти AUTO_INCREMENT=3
, указывает, что идентификатор был сгенерирован, но не использовался в строке.
принимая во внимание, что REPLACE
действительно удаляет исходную строку и вставляет новую строку, генерируя и хранение нового автоинкрементного идентификатора:
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 1 | 20 |
+----+------+
mysql> replace into foo (u) values (20);
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 3 | 20 |
+----+------+
Я обычно использую INSERT IGNORE
, и это походит точно на вид поведения, которое Вы ищете также. Пока Вы знаете, что строки, которые вызвали бы индексные конфликты, не будут вставлены, и Вы планируете свою программу соответственно, она не должна доставлять неприятности.
Replace
В походит на опцию. Или можно свериться
IF NOT EXISTS(QUERY) Then INSERT
, Это вставит или удалит, затем вставляют. Я склонен идти для IF NOT EXISTS
проверка сначала.
НА ДУБЛИРУЮЩЕМСЯ КЛЮЧЕВОМ ОБНОВЛЕНИИ не действительно в стандарте. Это почти столь стандартно, как ЗАМЕНА. См. СЛИЯНИЕ SQL .
По существу обе команды являются версиями альтернативного синтаксиса стандартных команд.