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

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

Например:

INSERT INTO table_name (ID, NAME, AGE) VALUES(1, "A", 19);

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


person Keshan    schedule 17.11.2010    source источник
comment
Для этого варианта использования SQL требуется официальный синтаксис, который не вызывает дублирования значений в синтаксисе и сохраняет первичный ключ.   -  person Pete Alvin    schedule 26.01.2018
comment
Чтобы узнать идентификатор, на который влияют, обратитесь к MySQL ON DUPLICATE KEY - последний идентификатор вставки?   -  person LF00    schedule 24.04.2019
comment
Предупреждение: начиная с версии 5.7 этот подход не поддерживает напрямую предложение WHERE как часть операции INSERT / UPDATE. Кроме того, UPDATE фактически считается двумя отдельными операциями (DELETE и INSERT) ... в случае, если это имеет значение для целей аудита. (Learnbit)   -  person dreftymac    schedule 11.07.2019


Ответы (11)


Используйте INSERT ... ON DUPLICATE KEY UPDATE.

ЗАПРОС:

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE    
name="A", age=19
person Donnie    schedule 17.11.2010
comment
+1 Из того, что я обнаружил, этот метод менее проблематичен для ключей с автоинкрементом и других конфликтов уникальных ключей, чем REPLACE INTO, и более эффективен. - person Andrew Ensley; 12.05.2012
comment
Отличный ответ и ссылка. Этот метод лучше всего, поскольку он проверяет PRIMARY ключи, UNIQUE индексы и столбцы с автоматическим приращением. Таким образом, INSERT INTO table (a,b,c) VALUES (NULL, "A", 19) все равно вызовет событие обновления. - person The Thirsty Ape; 17.07.2013
comment
Я знаю, что все вы намекаете на это, но я хочу быть откровенным для других. Если введенный вами идентификатор НЕ ЯВЛЯЕТСЯ ПЕРВИЧНЫМ КЛЮЧОМ или УНИКАЛЬНЫМ, это не сработает. Сначала это не сработало для меня, потому что мой идентификатор не был уникальным. - person Keven; 05.12.2013
comment
Интересно, почему affected row count приводит к 2 при успешном обновлении (по повторяющемуся ключу) одной строки? У кого-нибудь еще был такой результат? (Данные обновляются правильно: это означает, что обновляется только 1 строка) - person Dimitry K; 20.02.2014
comment
Дмитрий К, - подтвердил. При обновлении результат иногда сообщает о двух запросах (хотя у меня в таблице был только один). Иногда он сообщает 0 (!) Затронутых строк. Вставка всегда влияет на одну строку. Однако я не понимаю, почему это так. - person ılǝ; 31.03.2014
comment
Это немного поздно, но в любом случае: это указано в manual, который обновляется в ON DUPLICATE KEY UPDATE, увеличивает затронутые строки на 2. Он сообщает 0, если на самом деле ничего не обновляется (то же самое, что и обычный UPDATE). - person Vatev; 31.03.2014
comment
Есть ли способ объединить это с несколькими вставками (используя один оператор INSERT)? MSSQL позволяет вставлять до 1000 строк с помощью 1 оператора, и мне действительно нужно это сделать, но с использованием этого ответа. - person dominicbri7; 18.07.2014
comment
Есть ли способ узнать, какой запрос был запущен? Я хочу сохранить его в виде логического значения и обработать соответствующим образом. Установите логическое значение вставки в значение true, если в противном случае дубликат ключа не был найден ложным. - person harishannam; 12.02.2015
comment
Идеально! Спасибо! Я сначала использовал в транзакции UPDATE, если 0 строка затронула INSERT, прежде чем увидеть это! - person LINKeRxUA; 27.05.2015
comment
Как проверить (ЕСЛИ НЕ СУЩЕСТВУЕТ) два столбца одновременно? - person Iman Marashi; 25.09.2015
comment
Причина, по которой он иногда говорит, что затронуты 2 строки, заключается в том, чтобы вы могли определить, была ли выполнена вставка или обновление. Затронутая 1 строка = вставка, 2 затронутые строки = обновление. dev.mysql.com/doc/refman/5.0/ ru / insert-on-duplicate.html - person Mikhail Janowski; 23.11.2015
comment
хм, у меня не работает .. синтаксическая ошибка рядом с 'ON' .. установка уникального поля и удаление / воссоздание дает тот же результат для моих ‹50 наборов данных :) - person Martin Pfeffer; 29.12.2015
comment
У меня есть несколько полей, поэтому похоже, что этот метод приведет к огромному вызову привязки (PHP / mysqli). Я собираюсь исследовать REPLACE - в комментариях есть несколько предостережений, но все, похоже, подходит для моего приложения. - person winwaed; 30.01.2016
comment
Также обратите внимание, что вы можете использовать VALUES (name) для ссылки на значение, которое вы пытаетесь вставить, например INSERT INTO table (id, name, age) VALUES (1, A, 19) ON DUPLICATE KEY UPDATE name = VALUES (name), age = VALUES (age) - person Curious Sam; 01.03.2016
comment
@Donnie и другие, я хочу использовать этот запрос, но хочу проверить, есть ли запись для project_id = pId и expert_id = eId, затем ОБНОВИТЬ ml_match, иначе INSERT project_id, expert_id, ml_match и игнорировать другие столбцы. Вы можете написать запрос? ON DUPLICATE KEY UPDATE работает только с первичным ключом или любым именем поля? - person Khalid Usman; 26.11.2016
comment
Хорошо сделано для гибкости запросов, просто объединение в конце вставки. - person Dadan; 01.12.2016
comment
эй, друзья, я хочу проверить, что имя доступно в базе данных и доступно, затем замените возраст, в противном случае вставьте запись - person Pankaj Talaviya; 05.01.2017
comment
Имейте в виду, что существует проблема с обновлением On Duplicate Key. В случае сбоя по какой-либо причине идентификатор автозаполнения все равно автоматически увеличивается, даже если данные не добавляются. По этой причине я этим не пользуюсь. Я просто проверяю, есть ли текущий идентификатор. Если есть, я обновляю, а если нет идентификатора, я вставляю. - person Thomas Williams; 09.01.2017
comment
@Keven Отличный момент, хотя если ваш идентификатор не уникален, это не идентификатор, не так ли? : D Вы можете сказать, что его появление в таблице не является уникальным, но вы не можете сказать, что идентификатор не является уникальным x) ... - person jave.web; 30.01.2017
comment
@ ersks - это явно конструкция MySQL. Если это не работает, ваша схема таблицы не соответствует тому, что вы пытались сделать, или вы ее неправильно используете. - person Donnie; 31.07.2017
comment
@Donnie, Работает нормально. Спасибо. - person Ram; 20.04.2018
comment
@abdullahbd Это неверно. При дублировании ключа UPDATE обновляет, а не удаляет. В противном случае первичный ключ изменится (REPLACE INTO удаляет и вставляет). Затронутые строки - это просто код возврата. 1 строка означает, что вы вставили, 2 означает, что вы обновили, 0 означает, что ничего не произошло. (Это также задокументировано в документации mysql) - person Donnie; 18.05.2020
comment
мощное решение просто сэкономило несколько недель, я думаю :) - person spetsnaz; 08.09.2020

Проверить ЗАМЕНИТЬ

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

REPLACE into table (id, name, age) values(1, "A", 19)
person Martin Schapendonk    schedule 17.11.2010
comment
@Piontek Потому что это короче и проще для понимания, и никто не объяснил, почему вставка на дубликате лучше. - person Mr_Chimp; 13.06.2013
comment
он изменяет идентификаторы записи и, таким образом, может уничтожить внешние ссылки. - person boh; 13.09.2013
comment
Другая проблема с REPLACE INTO заключается в том, что вы должны указать значения для ВСЕХ полей ... иначе поля будут потеряны или заменены значениями по умолчанию. REPLACE INTO по существу удаляет строку, если она существует, и вставляет новую строку. В этом примере, если вы сделали 'REPLACE INTO table (id, age) values ​​(1, 19), тогда поле имени станет нулевым. - person Dale; 08.12.2013
comment
На самом деле это УДАЛЕНИЕ всей строки и выполнение новой ВСТАВКИ. - person mjb; 12.06.2014
comment
@mjb Следовательно, вам нужны привилегии DELETE, которых лучше не иметь, если они вам не нужны. Пользователь базы данных моей среды имеет только разрешения INSERT и UPDATE, поэтому REPLACE не будет работать. - person ndm13; 05.06.2015
comment
Он не изменяет идентификатор записи, но удаляет запись, а затем повторно вставляет ее при совпадении, что MySQL воспринимает как нарушающие внешние ключи. - person Thomas Andrews; 04.02.2016

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

INSERT INTO TABLE (id, name, age) VALUES (1, "A", 19), (2, "B", 17), (3, "C", 22)
ON DUPLICATE KEY UPDATE
    name = VALUES (name),
    ...
person Fabiano Souza    schedule 27.01.2017
comment
Если VALUES(name) не работает, вы можете попробовать name = 'name_value',...; - person Son Pham; 21.04.2020
comment
VALUES теперь устарел - вы должны использовать вставку в TABLE (Id, name, age) values ​​(1, A, 19), (2, B, 20) как ins для повторяющегося обновления ключа name = ins.name, age = ins. возраст; - person Liam; 04.06.2021

Любое из этих решений будет работать в отношении вашего вопроса:

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

or

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

or

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

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

person Dilraj Singh    schedule 07.12.2017
comment
REPLACE не задокументирован в связанном документе. - person Ray Baxter; 13.03.2018
comment
sql-запросы полны опечаток, ваши примеры не сработают. Это INSERT INTO TABLE (не INTO TABLE) и ON DUPLICATE KEY UPDATE (не ON DUPLICATE UPDATE SET). Не уверен, кто голосует за это - person Robert Sinclair; 02.11.2018
comment
Приносим извинения за ошибку опечаток. Спасибо, что поправили меня - person Dilraj Singh; 29.11.2018
comment
Как INSERT IGNORE здесь будет работать? Он просто игнорирует ошибку вставки и НЕ выполняет обновление, поэтому никоим образом не может рассматриваться как ответ на вопрос OP. - person RAM237; 25.02.2021

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

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

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

person Luis Reyes    schedule 17.11.2010
comment
на самом деле мне не нужно добавлять новые значения в другую строку с новым идентификатором, вместо этого я хочу заменить существующие значения id = 1 этими значениями. (насколько я понимаю, это увеличивает идентификатор и добавляет данные) - person Keshan; 17.11.2010
comment
Я не думаю, что он хочет увеличивать идентификатор на единицу для дубликатов. - person Donnie; 17.11.2010
comment
Это лучший ответ IMO, поскольку он нарушает все разновидности SQL, а не только MySQL. - person Fandango68; 28.10.2015
comment
«проступок» - это не то слово, которое вы ищете :) К сожалению, теперь я увидел проступок, я больше не могу представить себе истинное слово .. - person mwfearnley; 13.04.2017
comment
Вы искали траверсы или обложки? - person Chris Dev; 28.06.2017
comment
@mwfearnley Слово, которое вы пытались визуализировать, трансцендирует. Всего полтора года :-) - person Michael Krebs; 03.09.2018

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

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

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

person Rasel    schedule 27.08.2014
comment
Я хочу работать без использования id. Вы пробовали без первичного ключа? - person ersks; 06.07.2017
comment
@ersks видят вопрос. пользователь спросил, когда есть уникальный ключ - person Rasel; 09.07.2017
comment
Я получил это, но я пытаюсь решить свою проблему, в которой известны только эти значения. Итак, в такой ситуации я написал выше комментарий в надежде на правильное решение. - person ersks; 13.07.2017

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

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

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

person DawnSong    schedule 17.11.2016
comment
Что делает replace into, так это вставляет или обновляет, когда существует. @Сова - person DawnSong; 17.11.2016
comment
+1 (1 из 3) Я обнаружил, что это работает в моей ситуации - мне нужно было заменить существующую строку уникальным ключом или, если его нет, добавить строку. Здесь самое простое решение. - person therobyouknow; 30.01.2017
comment
(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(); - person therobyouknow; 30.01.2017
comment
(3 из 3) Связанный вопрос / ответ stackoverflow.com/questions/41767517/ - person therobyouknow; 30.01.2017
comment
Проблема с этим в mysql заключается в том, что replace удалит другие значения, если они не указаны. Однако решение @ fabiano-souza более подходящее. - person Quamber Ali; 21.03.2018

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

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, хотя я согласен, что это, вероятно, лучше.

person SteveCinq    schedule 09.06.2017

В случае, если вы хотите сделать 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)
person Rich    schedule 22.05.2020
comment
Я пробовал это, я получаю сообщение об ошибке, в котором говорится, что столбец BLOB / TEXT 'column_name' используется в спецификации ключа без длины ключа - person Natalia; 21.10.2020
comment
@Natalia любезно создайте dbfiddle, чтобы я мог проверить - person Rich; 21.10.2020
comment
Я попробую, но в принципе, вы не можете сделать текстовый тип столбца уникальным в MySQL. Я сделал это варчар. - person Natalia; 21.10.2020

В моем случае я создал запросы ниже, но в первом запросе, если id 1 уже существует, а возраст уже есть, после этого, если вы создадите первый запрос без 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

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

person Renish Gotecha    schedule 05.02.2019
comment
Кто-нибудь знает, почему мы должны назначать значения дважды? Почему MySQL не позволяет нам завершить запрос на ON DUPLICATE KEY UPDATE без дублирования всех операторов присваивания? В некоторых таблицах базы данных есть много столбцов, и это кажется избыточным / ненужным. Я понимаю, почему у нас есть возможность альтернативных назначений, но почему бы не отказаться от них? Просто любопытно, знает ли кто. - person ; 15.05.2019

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

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE    
name=name, age=19;
person Xman Classical    schedule 16.08.2019