MySQL "хороший" способ вставить строку, если она не найдена, или обновить ее, если она найдена - PullRequest
15 голосов
/ 18 апреля 2009

Очень часто я хочу выполнить запрос для одного из моих пользователей, где я хочу, чтобы строка сохранялась и ассоциировалась с этим пользователем в отношении 1: 1. Допустим (это просто произвольный пример), что у меня есть таблица, которая отслеживает автомобиль пользователя, а также некоторую информацию об автомобиле. У каждого пользователя может быть 0 или 1 машина. Если у пользователя нет автомобиля, в таблице нет записи для этого пользователя.

Таблица

автомобилей (опять же, просто пример): id, user_id, car_make, car_model

Итак, когда я обновляю эту таблицу, я всегда получаю что-то вроде этого (псевдокод):

result = SELECT * FROM cars WHERE user_id=5
if (num_rows(result)>0){
    UPDATE cars SET car_make='toyota', car_model='prius' WHERE user_id=5
}else{
    INSERT INTO cars (user_id, car_make, car_model) VALUES (5, 'toyota', 'prius')
}

Как я могу превратить это в одно изящное утверждение, которое работает «атомарно»? Что произойдет, если в другом процессе строка УДАЛЕНА между операторами SELECT и UPDATE? Мой оператор UPDATE потерпит неудачу там, где должен был выполняться оператор INSERT. И я чувствую, что мне нужно сделать два похожих (но разных) утверждения, чтобы выполнить одно и то же! Что мне нужно, так это какое-то утверждение, которое убедит меня в том, что нужные мне данные существуют в таблице, особенно когда мне нужна только 1 строка, которая удовлетворяет моим требованиям. Например, это может быть что-то вроде (конечно, это полностью выдумано):

MAKE SURE A ROW IN cars WHERE user_id=5 IS SET WITH car_make='toyota', car_model='prius'

Таким образом, если user_id из 5 уже существует, он будет обновлен, в противном случае он будет вставлен. Кроме того, если бы я изменил требования, например, чтобы сказать, что у каждого пользователя может быть ноль или одна машина данного car_make, то я мог бы дополнительно указать, что:

MAKE SURE A ROW IN cars WHERE user_id=5 AND car_make='toyota' IS SET WITH car_model='prius'

Надеюсь, мой вопрос имеет смысл! Как я могу улучшить эту базовую операцию вставки, если не найден или обновить, если найден, которая возникает так часто? Спасибо за любую помощь!

Ответы [ 6 ]

17 голосов
/ 18 апреля 2009

Вы можете использовать « REPLACE INTO » или « INSERT… ON DUPLICATE KEY UPDATE ». Я полагаю, что второе - это то, что вы хотите, но есть ситуации, когда REPLACE INTO удобно.

6 голосов
/ 25 июня 2009

С мой другой ответ переполнения стека :

Если вы хотите сделать это в одном выражении, я бы рекомендовал использовать синтаксис INSERT ... ON DUPLICATE KEY UPDATE следующим образом:

INSERT INTO table (id, someothervalue) VALUES (1, 'hi mom')
  ON DUPLICATE KEY UPDATE someothervalue = 'hi mom';

Первоначальный оператор INSERT будет выполнен, если не существует существующей записи с указанным значением ключа (либо первичным ключом, либо уникальным). Если запись уже существует, выполняется следующий оператор UPDATE (someothervalue = 3).

Это поддерживается во всех версиях MySQL. Для получения дополнительной информации см. Страницу справочного руководства MySQL для INSERT ... ON DUPLICATE KEY UPDATE

2 голосов
/ 18 апреля 2009

Это называется UPSERT ( UP дата или SERT ). Есть несколько вопросов по этому вопросу, которые вы можете найти. См. Википедию

РЕДАКТИРОВАНИЕ: MySQL 4.1+ поддерживает INSATE ( INS ert или upd ATE ), что должно дать вам то же самое, если у вас основной ключ. MySQL Manual

1 голос
/ 18 апреля 2009

Я думаю, что это легче переключить. Попробуйте вставить, затем обновить.

В MySQL есть пункт «ON DUPLICATE KEY»

ВСТАВИТЬ В АВТО (поля) ЗНАЧЕНИЯ (значения) ОБНОВЛЕНИЕ КЛЮЧЕВОГО КЛЮЧА ...

Это, конечно, требует правильной настройки уникальных ключей.

0 голосов
/ 18 апреля 2009

пример того, как я использовал ON DUPLICATE KEY UPDATE: INSERT INTO реестр (имя, значение) ЗНАЧЕНИЯ ('". $ Key."', '". $ Val."') ON DUPLICATE KEY UPDATE значение = '". $ Val."' "

0 голосов
/ 18 апреля 2009

В Oracle у вас есть Слияние .

Понятия не имею в MySql, но этот термин может дать вам что-то еще для поиска.

...