Вставить в таблицу MySQL или обновить, если существует

875

Я хочу добавить строку в таблицу базы данных, но если строка существует с тем же уникальным ключом, я хочу обновить строку.

Например:

insert into table (id, name, age) values(1, "A", 19)

Допустим, уникальный ключ есть id, и в моей базе данных есть строка с id = 1. В этом случае я хочу обновить эту строку этими значениями. Обычно это дает ошибку.
Если я использую insert IGNOREего, он будет игнорировать ошибку, но все равно не будет обновляться.

Keshan
источник
6
Для этого варианта использования SQL требуется официальный синтаксис, который не вызывает дублирования значений в синтаксисе и сохраняет первичный ключ.
Пит Элвин
Чтобы получить идентификатор, на который влияют, обратитесь к КЛЮЧУ НА ДУБЛИКАТЕ MySQL - последний идентификатор вставки?
Крис Руф
Предостережение: начиная с версии 5.7 этот подход напрямую не поддерживает предложение WHERE как часть операции INSERT / UPDATE. Кроме того, UPDATE фактически считается двумя отдельными операциями (DELETE и INSERT) ... в случае, если это имеет значение для целей аудита. (Learnbit)
dreftymac

Ответы:

1600

использование INSERT ... ON DUPLICATE KEY UPDATE

QUERY:

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE    
name="A", age=19
Donnie
источник
86
+1 Из того, что я нашел, этот метод менее проблематичен для ключей автоинкремента и других уникальных коллизий ключей, чем REPLACE INTO, и он более эффективен.
Эндрю Энсли
46
Я знаю, что вы все намекаете на это, но я хочу быть откровенным для других. Если ID, который вы вводите, НЕ является ПЕРВИЧНЫМ КЛЮЧОМ или УНИКАЛЬНЫМ, то это не будет работать. Это изначально не работало для меня, потому что мой идентификатор не был уникальным.
Кевен
7
Интересно, почему это affected row countприводит к 2успешному обновлению (на дубликате ключа) одной строки? У кого-нибудь еще был такой результат? (Данные обновлены правильно: имеется в виду только 1 строка)
Dimitry K
15
Это немного поздно, но в любом случае: в руководстве указано, что обновления ON DUPLICATE KEY UPDATEувеличивают затронутые строки на 2. Он сообщает 0, если на самом деле ничего не обновляется (то же самое, что и обычное UPDATE).
Ватев
61
Также обратите внимание, что вы можете использовать VALUES (имя) для ссылки на значение, которое вы пытаетесь вставить, например, INSERT INTO table (id, name, age) VALUES (1, "A", 19) ON DUPLICATE KEY UPDATE name = VALUES (name) , возраст = ЦЕННОСТИ (возраст)
Любопытно Сэм
246

Проверьте ЗАМЕНА

http://dev.mysql.com/doc/refman/5.0/en/replace.html

REPLACE into table (id, name, age) values(1, "A", 19)
Мартин Шапендонк
источник
11
@Piontek Потому что этот короче и его легче понять, и никто не объяснил, почему лучше «вставить на дубликат».
Mr_Chimp
77
он изменяет идентификаторы записи и, таким образом, может уничтожать внешние ссылки.
Boh
102
Другая проблема с REPLACE INTO заключается в том, что вы должны указать значения для ВСЕХ полей ... в противном случае поля будут потеряны или заменены значениями по умолчанию. REPLACE INTO по существу удаляет строку, если она существует, и вставляет новую строку. В этом примере, если вы сделали 'REPLACE INTO table (id, age) значения (1, 19), то поле имени станет пустым.
Дейл
33
Это на самом деле УДАЛИТЬ всю строку и выполнить новую вставку.
mjb
8
@mjb Следовательно, вам нужно иметь привилегии DELETE, которых лучше не иметь, если они вам не нужны. Пользователь базы данных моей среды имеет только разрешения INSERT и UPDATE, поэтому REPLACE не будет работать.
ndm13
54

При использовании пакетной вставки используйте следующий синтаксис:

INSERT INTO TABLE (id, name, age) VALUES (1, "A", 19), (2, "B", 17), (3, "C", 22)
ON DUPLICATE KEY UPDATE
    name = VALUES (name),
    ...
Фабиано Соуза
источник
Очень полезно, если вы хотите манипулировать новым значением
Голод
Если VALUES(name)не работает, вы можете попробоватьname = 'name_value',...;
Сон Фам
26

Попробуйте это:

INSERT INTO table (id, name, age) VALUES (1, 'A', 19) ON DUPLICATE KEY UPDATE id = id + 1;

Надеюсь это поможет.

Луис Рейес
источник
6
на самом деле мне не нужно добавлять новые значения в другую строку с новым идентификатором, вместо этого я хочу заменить существующие значения id = 1 на эти значения. (насколько я понимаю, это увеличивает идентификатор и добавляет данные)
Кешан
49
Я не думаю, что он хочет увеличить идентификатор на дубликаты.
Донни
7
"transgress" - это не то слово, которое вы ищете :) К сожалению, теперь я увидел "transgress", я больше не могу визуализировать фактическое слово ..
mwfearnley
1
Вы искали "траверсы" или "чехлы"?
Крис Дев
4
@mwfearnley Слово, которое вы пытались визуализировать, это «превосходит». Прошло всего полтора года :-)
Майкл Кребс
20

Попробуй это:

INSERT INTO table (id,name,age) VALUES('1','Mohammad','21') ON DUPLICATE KEY UPDATE name='Mohammad',age='21'

Примечание.
Здесь, если id является первичным ключом, после первой вставки при id='1'каждой попытке вставки id='1'обновляются имя и возраст, а предыдущий возраст имени изменяется.

Rasel
источник
Я хочу работать без использования идентификатора . Вы пробовали без первичного ключа?
Ersks
@ersks смотри вопрос. пользователь спросил о том, когда есть уникальный ключ
Rasel
Я понял это, но я пытаюсь решить мою проблему, в которой известны только эти ценности. Итак, в такой ситуации я написал выше комментарий в надежде на правильное решение.
Ersks
15
INSERT IGNORE INTO table (id, name, age) VALUES (1, "A", 19);

INSERT INTO TABLE (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE NAME = "A", AGE = 19;

REPLACE INTO table (id, name, age) VALUES(1, "A", 19);

Все эти решения будут работать в отношении вашего вопроса.

Если вы хотите узнать подробнее об этом заявлении, перейдите по этой ссылке

Дилрадж Сингх
источник
REPLACEне документировано в связанном документе.
Рэй Бакстер
SQL-запросы полны опечаток, ваши примеры не будут работать. Это INSERT INTO TABLE (не INTO TABLE) и ON DUPLICATE KEY UPDATE (не ON DUPLICATE UPDATE SET). Не уверен, кто голосует против этого
Роберт Синклер
1
Извините за опечатки. Спасибо за исправление меня
Дилрадж Сингх
11

При использовании SQLite:

REPLACE into table (id, name, age) values(1, "A", 19)

При условии, что idэто первичный ключ. Или же он просто вставляет другой ряд. Смотрите INSERT (SQLite).

DawnSong
источник
Что именно replace intoозначает «вставить или обновить, если есть». @Owl
DawnSong
+1 (1 из 3) Я обнаружил, что это работает для моей ситуации - мне нужно было заменить существующую строку уникальным ключом или, если ее там нет, добавить строку. Самые простые решения здесь.
therobyouknow
(2 из 3) Мой запрос:CREATE TRIGGER worklog_update AFTER INSERT ON worklog FOR EACH ROW REPLACE INTO support_time_monthly_hours ( ProjectID, monthTotalTime, Year, Month ) SELECT jiraissue.PROJECT, SUM(worklog.timeworked), YEAR(CURRENT_DATE()), MONTH(CURRENT_DATE()) FROM worklog, jiraissue WHERE worklog.issueid = jiraissue.ID AND jiraissue.PROJECT = (SELECT PROJECT FROM jiraissue WHERE NEW.issueid = jiraissue.ID ) AND worklog.startdate BETWEEN DATE_FORMAT(NOW() ,'%Y-%m-01 00:00:00') AND NOW();
therobyouknow
(3 из 3) Связанный вопрос / ответ stackoverflow.com/questions/41767517/…
therobyouknow
2
Проблема с этим в MySQL состоит в том, что замена удалит другие значения, если они не предоставлены. Однако решение @ fabiano-souza более уместно
Quamber Ali
11

Просто потому, что я искал здесь это решение, но для обновления из другой идентично структурированной таблицы (в моем случае тестовая БД веб-сайта для живой БД):

INSERT  live-db.table1
SELECT  *
FROM    test-db.table1 t
ON DUPLICATE KEY UPDATE
        ColToUpdate1 = t.ColToUpdate1,
        ColToUpdate2 = t.ColToUpdate2,
        ...

Как уже упоминалось, только столбцы, которые вы хотите обновить, должны быть включены после ON DUPLICATE KEY UPDATE.

Нет необходимости перечислять столбцы в INSERTили SELECT, хотя я согласен, что это, вероятно, лучшая практика.

SteveCinq
источник
4

В случае, если вы хотите создать non-primaryполя в качестве критерия / условия ON DUPLICATE, вы можете сделать UNIQUE INDEXключ в этой таблице, чтобы вызвать DUPLICATE.

ALTER TABLE `table` ADD UNIQUE `unique_index`(`name`);

И если вы хотите объединить два поля, чтобы сделать его уникальным в таблице, вы можете добиться этого, добавив больше в последний параметр.

ALTER TABLE `table` ADD UNIQUE `unique_index`(`name`, `age`);

Обратите внимание, просто убедитесь , что для удаления первого всех данных , которые имеют то же самое nameи ageзначение по другим строкам.

DELETE table FROM table AS a, table AS b WHERE a.id < b.id 
AND a.name <=> b.name AND a.age <=> b.age;

После этого должно запуститься ON DUPLICATEсобытие.

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE    
name = VALUES(name), age = VALUES(age)
Богатые
источник
2

В моем случае я создал следующие запросы, но в первом запросе, если id1 уже существует и возраст уже существует, после этого, если вы создадите первый запрос без, ageзначение не ageбудет равняться

REPLACE into table SET `id` = 1, `name` = 'A', `age` = 19

чтобы избежать вышеуказанной проблемы, создайте запрос, как показано ниже

INSERT INTO table SET `id` = '1', `name` = 'A', `age` = 19 ON DUPLICATE KEY UPDATE `id` = "1", `name` = "A",`age` = 19

может это поможет тебе ...

Рениш Готеча
источник
2
Кто-нибудь знает, почему мы должны присвоить значения дважды? Почему MySQL не позволяет нам завершить запрос в ON DUPLICATE KEY UPDATE без дублирования всех операторов присваивания? В некоторых таблицах базы данных есть много столбцов, и это кажется избыточным / необоснованным. Я понимаю, почему у нас есть возможность для альтернативных назначений, но почему бы не иметь возможность также опустить их? Просто любопытно, если кто-нибудь знает.
Голубая вода
2

В случае, если вы хотите сохранить старое поле (например, имя). Запрос будет:

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE    
name=name, age=19;
Xman Классика
источник