MySQL "хороший" способ вставить строку, если не найден, или обновить ее, если она найдена

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

car table (опять же, пример): 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. И я чувствую, что мне нужно сделать два похожих (но разных) заявления, чтобы выполнить одно и то же! Мне нужна инструкция, которая заверит меня, что данные, которые я хочу, существуют в таблице, особенно когда мне нужна только одна строка, которая удовлетворяет моим требованиям. Например, это может быть что-то вроде этого (это, конечно, полностью сделано):

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'

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

Ответы

Ответ 2

От мой другой ответ:

Если вы хотите сделать это в одном выражении, я бы рекомендовал использовать синтаксис 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

Ответ 3

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

EDIT: MySQL 4.1+ поддерживает INSATE (INSert или updATE), который должен получить то же самое, если у вас есть первичный ключ. Руководство по MySQL

Ответ 4

Мне кажется, что проще переключить его. Попробуйте вставить, а затем обновить.

У MySQL есть специальное предложение "ON DUPLICATE KEY"

INSERT INTO cars (поля) VALUES (значения) ON DUPLICATE KEY UPDATE...

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

Ответ 5

В Oracle у вас Merge.

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

Ответ 6

пример того, как я использовал ON DUPLICATE KEY UPDATE: INSERT INTO (имя, значение) VALUES (' ". $Key." ', ' ". $Val." ') ON DUPLICATE KEY UPDATE value = ' ". $Val." ' "