На оновлення повторюваного ключа аналогічно вставці


158

Я шукав навколо, але не знайшов, чи можливо.

У мене цей запит MySQL:

INSERT INTO table (id,a,b,c,d,e,f,g) VALUES (1,2,3,4,5,6,7,8)

Ідентифікатор поля має "унікальний індекс", тому їх не може бути два. Тепер, якщо той самий ідентифікатор вже є в базі даних, я хотів би оновити його. Але чи справді мені знову потрібно вказати всі ці поля, як-от:

INSERT INTO table (id,a,b,c,d,e,f,g) VALUES (1,2,3,4,5,6,7,8) 
ON DUPLICATE KEY UPDATE a=2,b=3,c=4,d=5,e=6,f=7,g=8

Або:

INSERT INTO table (id,a,b,c,d,e,f,g) VALUES (1,2,3,4,5,6,7,8) 
ON DUPLICATE KEY UPDATE a=VALUES(a),b=VALUES(b),c=VALUES(c),d=VALUES(d),e=VALUES(e),f=VALUES(f),g=VALUES(g)

Я все вказав уже у вставці ...

Додаткову записку, я хотів би використати роботу, щоб отримати посвідчення особи!

id=LAST_INSERT_ID(id)

Я сподіваюся, що хтось може сказати мені, який спосіб є найефективнішим.


9
AFAIK - метод перезавантаження кожного стовпця a=VALUES(a), b=VALUES(b), ...- це шлях, який потрібно пройти. Ось так я це роблю для всіх своїх INSERT ON DUPLICATE KEY UPDATEвисловлювань.
Valdogg21

4
Просто для уточнення, все сказане тут є правильним, доки ви розумієте, на що відповіли на це питання: чи потрібно перезавантажувати кожен стовпець, який хочете оновити? Так, якщо ви хочете вставити або оновити 8 стовпців у таблиці з 25 стовпцями, ви повинні вказати 8 стовпців двічі - один раз у частині вставки та один раз у частині оновлення. (Ви можете пропустити первинний ключ у частині оновлення, але найпростіше попередньо відформатувати рядок "a = 1, b = 2, c = 3" та вставити його двічі.) Однак вам НЕ доведеться перезавантажувати решту 17 стовпців ви не хочете змінюватися. Якщо він стане ОНОВЛЕНОМ, вони збережуть існуючі значення.
Timberline

3
Я додав цей коментар, тому що питання та відповіді не впевнені у незгаданих стовпцях із подібним INSERT, які я потім перевірив, дізнавшись, що саме перевірити. ВСТАВКА НА ДУПЛІКАЦІЙНЕ КЛЮЧЕВНЕ ОНОВЛЕННЯ залишає незмінними стовпці в UPDATE, але надає їм значення INSERT за замовчуванням. Завдяки REPLACE INTO, згадані стовпці завжди отримують значення за замовчуванням, ніколи не існуючі.
Timberline

1
Перевірте stackoverflow.com/questions/2472229/… , я думаю, є те, що ви шукаєте
Chococroc

Відповіді:


82

UPDATEЗатвердження дається так , що старі поля можуть бути оновлені до нового значення. Якщо ваші старіші значення збігаються з вашими новими, навіщо вам це потрібно оновлювати?

Наприклад, наприклад. якщо ваші колонки aдо gвже встановлені як 2на 8; не потрібно було б її оновлювати.

Крім того, ви можете використовувати:

INSERT INTO table (id,a,b,c,d,e,f,g)
VALUES (1,2,3,4,5,6,7,8) 
ON DUPLICATE KEY
    UPDATE a=a, b=b, c=c, d=d, e=e, f=f, g=g;

Щоб отримати idвід LAST_INSERT_ID; потрібно вказати додаток, який ви використовуєте для того ж самого.

Для LuaSQL conn:getlastautoid()отримує значення.


6
Це лише для прикладу. У запиті реального життя є відмінності. Моє запитання тихо просте: чи мені дійсно потрібно вказати всі поля (та значення у моєму першому прикладі), якщо вони такі ж, як у вставці? Я просто хочу вставити все або, якщо є унікальна відповідність значення: оновити всіх.
Рой

1
"Додаткову записку, я також хотів би використати роботу, щоб отримати посвідчення особи!"
Агамемнус

1
@Tresdin, Наскільки я можу сказати, це просто синтаксичний цукор. Особисто я ніколи не бачив, щоб хтось використовував a = VALUES (a), b = VALUES (b) тощо. Можливо, ви можете призначити стовпчикові кілька значень? Не впевнений, чому ви не заздалегідь би просто об'єднали дані.
DuckPuncher

54
Якщо в таблиці tblвже є рядок (1,10), тоді: INSERT INTO tbl(id, a) VALUES(1,2) ON DUPLICATE KEY UPDATE a=VALUES(a)буде встановлено a = 2 . Поки INSERT INTO tbl(id, a) VALUES(1,2) ON DUPLICATE KEY UPDATE a=aбуде встановлено a = 10
Bùi Việt Thành

2
Чому всі нагороди? Це НЕ ПРАЦЮЄ. Як зазначав @ Bùi Việt Thành, a=aнічого не використовуючи, оновлення. (Запитання в оригінальному запитанні насправді нічого не оновлюють, але, здається, оновлення є те, що планувала ОП.)
Роджер

41

Існує специфічне розширення MySQL для SQL, яке може бути саме тим, що ви хочете - REPLACE INTO

Однак це не працює так само, як "ON DUPLICATE UPDATE"

  1. Він видаляє старий рядок, який стикається з новим рядком, а потім вставляє новий рядок. До тих пір, поки у вас немає первинного ключа на столі, це було б добре, але якщо ви це зробите, то якщо будь-яка інша таблиця посилається на цей первинний ключ

  2. Ви не можете посилатися на значення в старих рядках, щоб не могли зробити еквівалент

    INSERT INTO mytable (id, a, b, c) values ( 1, 2, 3, 4) 
    ON DUPLICATE KEY UPDATE
    id=1, a=2, b=3, c=c + 1;

Я хотів би використати роботу, щоб отримати посвідчення особи!

Це повинно працювати - last_insert_id () має мати правильне значення, доки ваш основний ключ автоматично збільшується.

Однак, як я вже сказав, якщо ви фактично використовуєте цей первинний ключ в інших таблицях, REPLACE INTOймовірно, для вас це не буде прийнятним, оскільки він видаляє стару рядок, що зіткнувся за допомогою унікального ключа.

Хтось ще запропонував, перш ніж можна зменшити набір тексту, виконуючи такі дії:

INSERT INTO `tableName` (`a`,`b`,`c`) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE `a`=VALUES(`a`), `b`=VALUES(`b`), `c`=VALUES(`c`);

Отже, я не можу дотримуватися первинного ключа перед replace intoзапитом?
Рой

Ні - цей рядок видалено та створено нову рядок, який матиме новий первинний ключ.
Данак

Ви не хочете, щоб це сповільнило процес на великих наборах даних і, як імпорт CSV-файлів зі 100K або більше рядків?
Мухаммед Омер Аслам

24

Іншого шляху немає, я мушу вказувати все двічі. Перший для вставки, другий у випадку оновлення.


9
Це невірно і відповідь не повинна бути прийнятою. Відповідь від @Danack - правильна відповідь.
Wayne Workman

2
Вам слід перечитати питання @WayneWorkman, це правильна відповідь.
Рой

24

Ось вирішення вашої проблеми:

Я намагався вирішити таку проблему, як ваша, і я хочу запропонувати протестувати з простого аспекту.

Виконайте наступні дії: Дізнайтеся про просте рішення.

Крок 1: Створіть схему таблиці за допомогою цього SQL-запиту:

CREATE TABLE IF NOT EXISTS `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(30) NOT NULL,
  `password` varchar(32) NOT NULL,
  `status` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `no_duplicate` (`username`,`password`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;

Таблиця <код> користувача </code> з даними

Крок 2: Створіть індекс з двох стовпців, щоб запобігти повторенню даних за допомогою наступного SQL-запиту:

ALTER TABLE `user` ADD INDEX no_duplicate (`username`, `password`);

або, Створіть з GUI індекс двох стовпців таким чином: Створення індексу з графічного інтерфейсу Виберіть стовпці, щоб створити індекс Покажчики таблиці <code> користувач </code>

Крок 3: Оновіть, якщо існує, вставте, якщо не використовуєте наступні запити:

INSERT INTO `user`(`username`, `password`) VALUES ('ersks','Nepal') ON DUPLICATE KEY UPDATE `username`='master',`password`='Nepal';

INSERT INTO `user`(`username`, `password`) VALUES ('master','Nepal') ON DUPLICATE KEY UPDATE `username`='ersks',`password`='Nepal';

Таблиця <code> user </code> після запуску над запитом


1
Дякую за цей посібник - зробив мене зрозумілим, високо оцінений, дякую!
Майкл Нільссон

Збереження паролів у простому тексті - жахлива ідея, оскільки намагається запобігти дублювання паролів на рівні бази даних.
OrangeDog

10

На всякий випадок, якщо ви зможете використовувати мову скриптів для підготовки своїх SQL запитів, ви можете повторно використовувати пари field = значення, використовуючи SETзамість (a,b,c) VALUES(a,b,c).

Приклад із PHP:

$pairs = "a=$a,b=$b,c=$c";
$query = "INSERT INTO $table SET $pairs ON DUPLICATE KEY UPDATE $pairs";

Приклад таблиці:

CREATE TABLE IF NOT EXISTS `tester` (
  `a` int(11) NOT NULL,
  `b` varchar(50) NOT NULL,
  `c` text NOT NULL,
  UNIQUE KEY `a` (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

4
Вам слід уникати своїх цінностей або виконувати підготовлений вислів зі своїми цінностями.
Chinoto Vokro

1
@ChinotoVokro - я згоден. Це просто представлення "як можна" і навіть не використовує жодних функцій запитів у прикладі.
Кріс

1
Це хороша альтернатива вказувати масив ключів та масив значень. Дякую.
Марк Карпентер-молодший

5

Ви можете розглянути можливість використання REPLACE INTOсинтаксису, але майте в виду, при дубліката ключа PRIMARY / UNIQUE, це анулює рядок і ПЛАСТИНИ новий.

Вам не потрібно буде повторно вказувати всі поля. Однак слід врахувати можливе зниження продуктивності (залежить від вашого дизайну таблиці).

Застереження:

  • Якщо у вас є первинний ключ AUTO_INCREMENT, йому буде наданий новий
  • Індекси, ймовірно, потрібно буде оновити

є порушення обмеження, якщо індекс також є іноземним ключем для іншої таблиці, він викликається видаленням частини.
користувач3290180

4

Я знаю, що вже пізно, але сподіваюся, що комусь допоможуть у цій відповіді

INSERT INTO t1 (a,b,c) VALUES (1,2,3),(4,5,6)
ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);

Ви можете прочитати підручник нижче:

https://mariadb.com/kb/en/library/insert-on-duplicate-key-update/

http://www.mysqltutorial.org/mysql-insert-or-update-on-duplicate-key-update/


Хороша відповідь. Але використання VALUES () для позначення нових рядків застаріло як у MySQL 8.0.20 . Новий підхід, детальний за посиланням, полягає у використанні псевдоніма для рядка. У цьому прикладі псевдонім new:INSERT INTO t1 (a,b,c) VALUES (1,2,3),(4,5,6) AS new ON DUPLICATE KEY UPDATE c = new.a+new.b;
user697473

@ user697473 Я отримую помилку: "У вас є помилка у вашому синтаксисі SQL; перевірте інструкцію, що відповідає вашій версії сервера MariaDB, чи правильно використовувати синтаксис" ЯК НОВИЙ НА ДУПЛІКАТИ КЛЮЧНОГО ОНОВЛЕННЯ a = new.a '" , і мій запит працював (за винятком випадків, коли виникали дублюючі ключі, очевидно), перш ніж я реалізував це застереження. Будь-які ідеї?
Аарон

@aaron - вибачте, немає чудових ідей. MySQL 8.0.20 щойно вийшов наприкінці квітня; можливо, MariaDB ще не наздогнав. Це може пояснити, чому це дає вам помилку.
користувач697473

@ user697473 Так, я фактично просто спробував метод a = VALUES (a) в оригінальній відповіді, і він спрацював, будь-ласка, спасибі.
аарон

-7

ви можете використовувати insert ignore для такого випадку, він буде ігнорувати, якщо отримає дублікати записів INSERT IGNORE ...; - без ВКЛЮЧЕНОГО КЛЮЧА


Я хотів вставити його, коли його немає, інакше оновити. Не ігноруйте це.
Рой

чому ви хочете оновити його, якщо ви оновлюєте попереднє / те саме значення, якщо його нове значення, то його добре з ним, якщо не вставити ігнорувати роботу для нього
pitu

2
Швидше за все, через те, що значення можуть змінюватися, і він хоче створити запис, якщо такого не існує, але оновити існуючий запис, якщо він буде (зі змінами) без накладних витрат на зворотну поїздку назад до програми, а потім назад до бази даних знову.
мопсид
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.