Я нашел несколько «подходящих» решений для классического «Как вставить новую запись или обновить ее, если она уже существует», но я не могу заставить ни одну из них работать в SQLite.
У меня есть таблица, определенная следующим образом:
CREATE TABLE Book
ID INTEGER PRIMARY KEY AUTOINCREMENT,
Name VARCHAR(60) UNIQUE,
TypeID INTEGER,
Level INTEGER,
Seen INTEGER
Что я хочу сделать, это добавить запись с уникальным именем. Если имя уже существует, я хочу изменить поля.
Может кто-нибудь сказать мне, как это сделать, пожалуйста?
Ответы:
Посмотрите на http://sqlite.org/lang_conflict.html .
Вы хотите что-то вроде:
Обратите внимание, что любое поле, отсутствующее в списке вставок, будет установлено в NULL, если строка уже существует в таблице. Вот почему есть выборка для
ID
столбца: в случае замены оператор установит его в NULL, а затем будет выделен новый идентификатор.Этот подход также может быть использован, если вы хотите оставить отдельные значения полей в одиночку, если строка в случае замены, но установить значение NULL в случае вставки.
Например, если вы хотите оставить в
Seen
покое:источник
Level
, этот подход не может быть использован.Вы должны использовать
INSERT OR IGNORE
команду, за которой следуетUPDATE
команда: В следующем примереname
это первичный ключ:Первая команда вставит запись. Если запись существует, она будет игнорировать ошибку, вызванную конфликтом с существующим первичным ключом.
Вторая команда обновит запись (которая теперь определенно существует)
источник
Вам нужно установить ограничение на таблицу, чтобы вызвать « конфликт », который вы затем разрешите, выполнив замену:
Тогда вы можете выдать:
«SELECT * FROM data» даст вам:
Обратите внимание, что data.id равен «3», а не «1», потому что REPLACE выполняет DELETE и INSERT, а не UPDATE. Это также означает, что вы должны убедиться, что вы определили все необходимые столбцы, иначе вы получите неожиданные значения NULL.
источник
Сначала обновите это. Если затронутое количество строк = 0, вставьте его. Это самый простой и подходящий для всех РСУБД .
источник
Insert or Replace
действительно более предпочтительным.INSERT OR REPLACE
заменит другие поля на значение по умолчанию.Если вы хотите сохранить другое поле
или используя UPSERT (синтаксис был добавлен в SQLite с версией 3.24.0 (2018-06-04))
В
excluded.
префикс равно значению вVALUES
.источник
Upsert это то, что вы хотите.
UPSERT
Синтаксис был добавлен в SQLite с версией 3.24.0 (2018-06-04).Имейте в виду, что на данном этапе фактическое слово «UPSERT» не является частью синтаксиса upsert.
Правильный синтаксис
INSERT INTO ... ON CONFLICT(...) DO UPDATE SET...
и если вы делаете
INSERT INTO SELECT ...
свой выбор, нужно хотя быWHERE true
решить неоднозначность синтаксического анализатора относительно токенаON
с синтаксисом соединения.Имейте в
INSERT OR REPLACE...
виду, что удалит запись перед вставкой новой, если ее придется заменить, что может быть плохо, если у вас есть каскады внешних ключей или другие триггеры удаления.источник
UPSERT
синтаксис.Если у вас нет первичного ключа, вы можете вставить, если не существует, а затем сделать обновление. Таблица должна содержать хотя бы одну запись перед использованием.
источник
Я верю, что ты хочешь UPSERT .
«INSERT OR REPLACE» без дополнительного обмана в этом ответе сбрасывает любые поля, которые вы не указали, в NULL или другое значение по умолчанию. (Такое поведение INSERT OR REPLACE отличается от UPDATE; оно в точности похоже на INSERT, потому что на самом деле это INSERT; однако, если вам нужно было UPDATE-if-существует, вы, вероятно, захотите семантику UPDATE и будете неприятно удивлены фактическим результатом.)
Хитрость из предложенной реализации UPSERT заключается в том, чтобы в основном использовать INSERT OR REPLACE, но указать все поля, используя встроенные предложения SELECT, чтобы получить текущее значение для полей, которые вы не хотите изменять.
источник
Я думаю, что стоит отметить, что здесь может быть какое-то неожиданное поведение, если вы не до конца понимаете, как PRIMARY KEY и UNIQUE взаимодействуют.
Например, если вы хотите вставить запись, только если поле ИМЯ в настоящее время не занято, и если это так, вы хотите, чтобы исключение ограничения срабатывало, чтобы сообщить вам, тогда INSERT OR REPLACE не будет выбрасывать и исключение и вместо этого будет разрешите само УНИКАЛЬНОЕ ограничение, заменив конфликтующую запись (существующая запись с тем же ИМЯ ). Гаспар очень хорошо демонстрирует это в своем ответе выше.
Если вы хотите, чтобы исключение ограничения сработало, вы должны использовать инструкцию INSERT и полагаться на отдельную команду UPDATE, чтобы обновить запись, как только вы узнаете, что имя не занято.
источник