Вставте в таблицю MySQL або оновіть, якщо вона існує


875

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

Наприклад:

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

Скажімо, унікальний ключ є id, і в моїй базі даних є рядок із id = 1. У такому випадку я хочу оновити цей рядок цими значеннями. Зазвичай це дає помилку.
Якщо я використовую, insert IGNOREвона буде ігнорувати помилку, але вона все одно не оновиться.


5
Для цього випадку SQL потрібен офіційний синтаксис, який не примушує дублювання значень у синтаксисі та зберігає первинний ключ.
Піт Елвін

Щоб отримати ідентифікатор під впливом, зверніться до MySQL ON DUPLICATE KEY - ідентифікатор останньої вставки?
Кріс Руф

Caveat: станом на версію 5.7 цей підхід не підтримує безпосередньо пункт WHERE як частину операції INSERT / UPDATE. Крім того, ОНОВЛЕННЯ насправді вважається двома окремими операціями (DELETE та INSERT) ... у випадку, якщо це має значення для цілей аудиту. (Learnbit)
dreftymac

Відповіді:


1599

Використовуйте INSERT ... ON DUPLICATE KEY UPDATE

ПИТАННЯ:

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

86
+1 З того, що я виявив, цей метод менш проблематичний для ключів з автоматичним збільшенням та інших унікальних зіткнень ключів, ніж ЗАМІНА ВІД, і він більш ефективний.
Ендрю Енслі

46
Я знаю, що ви всі на це натякаєте, але я хочу бути явним для інших. Якщо ідентифікатор, який ви вставляєте, НЕ ПЕРШИЙ КЛЮЧ або УНІКАЛЬНИЙ, то це не працює. Спочатку це не спрацювало для мене, оскільки мій посвідчення не було унікальним.
Кевен

7
Цікаво, чому це affected row countпризводить до 2успішного оновлення (на дублікат ключа) одного рядка? Хтось ще мав цей результат? (Дані оновлено правильно. Оновлено лише 1 рядок)
Dimitry K

14
Це трохи пізно, але все-таки: в посібнику зазначено, що оновлення ON DUPLICATE KEY UPDATEзбільшують уражені рядки на 2. Він повідомляє 0, якщо насправді нічого не оновлюється (як і звичайне UPDATE).
Ватев

61
Також зауважте, що ви можете використовувати VALUES (ім'я) для посилання на значення, яке ви намагаєтеся вставити, наприклад, ВСТАВИТИ INTO таблицю (ідентифікатор, ім'я, вік) 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_Cimimp

77
це змінює ідентифікатори запису і, таким чином, може знищувати іноземні посилання.
бог

102
Інша проблема REPLACE INTO полягає в тому, що ви повинні вказати значення для ВСІХ полів ... інакше поля втратяться або заміняться значеннями за замовчуванням. REPLACE INTO по суті видаляє рядок, якщо він існує, і вставляє новий рядок. У прикладі, якби ви "ЗАМІНУвали в таблицю (id, вік) значення (1, 19), то поле імені стане нульовим.
Дейл

33
Це фактично ВИДАЛИТИ весь рядок і виконувати новий ВСТУП.
mjb

8
@mjb Отже, вам потрібно мати DELETE привілеї, яких краще не мати, якщо вони вам не потрібні. Користувач бази даних мого середовища має лише дозволи INSERT та UPDATE, тож ЗАМІНА не працюватиме.
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',...;
Son Pham

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'буде оновлено ім'я, а вік і попередній вік імені змінюватимуться.


Я хочу працювати, не використовуючи id . Ви пробували без первинного ключа?
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 запитів, повних помилок, ваші приклади не працюватимуть. Це ВСТАВКА В ТАБЛИЦЮ (не В ТАБЛИЦЮ) та НА ДУПЛІКАТИВНУ КЛЮЧУ ОНОВЛЕННЯ (не НА ДУПЛІКАТНОМУ НАСТАВКІ ОНОВЛЕННЯ). Не впевнений, хто виступає за це
Роберт Сінклер

1
Вибачте за помилку друку. Дякуємо, що
виправили

11

Під час використання SQLite:

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

За умови, що idце первинний ключ. Або ж він просто вставляє інший рядок. Див. INSERT (SQLite).


Що 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, хоча я згоден, це, мабуть, краща практика.


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 не дозволяє нам закінчити запит у НАВЧАЛЬНОМУ ДУПЛІКАТУВАННІ КЛЮЧНОЇ ОНОВЛЕННЯ, не дублюючи всі заяви про призначення? У деяких таблицях бази даних є багато стовпців, і це здається зайвим / безоплатним. Я розумію, чому у нас є варіант альтернативних завдань, але чому б не було можливості їх також опустити? Просто цікаво, якщо хтось знає.
Блакитна вода

2

У випадку, якщо ви хочете зберегти старе поле (Наприклад, ім'я). Запит буде:

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE    
name=name, age=19;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.