ВСТАВИТЬ ЕСЛИ НЕ СУЩЕСТВУЕТ ДРУГОГО ОБНОВЛЕНИЯ?

Я нашел несколько" будет "решений для классического" как вставить новую запись или обновить ее, если она уже существует", но я не могу заставить их работать в SQLite.

У меня есть таблица определяется следующим образом:

CREATE TABLE Book 
ID     INTEGER PRIMARY KEY AUTOINCREMENT,
Name   VARCHAR(60) UNIQUE,
TypeID INTEGER,
Level  INTEGER,
Seen   INTEGER

Я хочу добавить запись с уникальным именем. Если имя уже существует, я хочу изменить поля.

может кто-нибудь сказать мне, как это сделать, пожалуйста?

8 ответов


посмотрите на http://sqlite.org/lang_conflict.html.

вы хотите что-то вроде:

insert or replace into Book (ID, Name, TypeID, Level, Seen) values
((select ID from Book where Name = "SearchName"), "SearchName", ...);

обратите внимание, что любое поле, отсутствующее в списке вставки, будет иметь значение NULL, если строка уже существует в таблице. Вот почему существует подселект для ID столбец: в случае замены оператор установит значение NULL, а затем будет выделен новый идентификатор.

этот подход также можно использовать, если вы хотите оставить конкретное поле только значения, если строка в случае замены, но установите для поля значение NULL в случае вставки.

например, если вы хотите оставить :

insert or replace into Book (ID, Name, TypeID, Level, Seen) values (
   (select ID from Book where Name = "SearchName"),
   "SearchName",
    5,
    6,
    (select Seen from Book where Name = "SearchName"));

вы должны использовать затем : В следующем примере name - это первичный ключ:

INSERT OR IGNORE INTO my_table (name, age) VALUES ('Karen', 34)
UPDATE my_table SET age = 34 WHERE name='Karen'

первая команда вставит запись. Если запись существует, она будет игнорировать ошибку, вызванную конфликтом с существующим первичным ключом.

вторая команда обновит запись (которая теперь определенно существует)


вам нужно установить ограничение на таблицу, чтобы вызвать"конфликт " который вы затем решите, выполнив замену:

CREATE TABLE data   (id INTEGER PRIMARY KEY, event_id INTEGER, track_id INTEGER, value REAL);
CREATE UNIQUE INDEX data_idx ON data(event_id, track_id);

тогда вы можете выпустить:

INSERT OR REPLACE INTO data VALUES (NULL, 1, 2, 3);
INSERT OR REPLACE INTO data VALUES (NULL, 2, 2, 3);
INSERT OR REPLACE INTO data VALUES (NULL, 1, 2, 5);

"выберите * из данных" даст вам:

2|2|2|3.0
3|1|2|5.0

обратите внимание, что данные.id - "3", а не" 1", потому что REPLACE выполняет удаление и вставку, а не обновление. Это также означает, что необходимо определить все необходимые столбцы, иначе будут получены непредвиденные значения NULL.


сначала обновите его. Если число затронутых строк = 0, то вставьте его. Его самый простой и подходит для всех СУБД.


INSERT OR REPLACE заменит другие поля (TypeID, Level) в значение по умолчанию.

INSERT OR REPLACE INTO book(id, name) VALUES(1001, 'Programming')

Я использую этот

INSERT OR IGNORE INTO book(id) VALUES(1001);
UPDATE book SET name = 'Programming' WHERE id = 1001;

вы также можете использовать

INSERT OR REPLACE INTO book (id, name) 
VALUES (1001, 'Programming',
  (SELECT typeid FROM book WHERE id = 1001),
  (SELECT level FROM book WHERE id = 1001),
)

но я думаю, что первый метод более легко читать


если у вас нет первичного ключа, вы можете вставить, если он не существует, а затем выполнить обновление. Таблица должна содержать по крайней мере одну запись перед использованием.

INSERT INTO Test 
   (id, name)
   SELECT 
      101 as id, 
      'Bob' as name
   FROM Test
       WHERE NOT EXISTS(SELECT * FROM Test WHERE id = 101 and name = 'Bob') LIMIT 1;

Update Test SET id='101' WHERE name='Bob';

Я считаю, что вы хотите UPSERT.

"вставить или заменить" без дополнительной хитрости в этом ответе сбросит любые поля, которые вы не укажете, на NULL или другое значение по умолчанию. (Это поведение INSERT или REPLACE не похоже на UPDATE; это точно так же, как INSERT, потому что это на самом деле INSERT; однако если вы хотите обновить-если-существует, вы, вероятно, хотите семантику обновления и будете неприятно удивлены фактическим результатом.)

обман от предлагаемая реализация UPSERT в основном использует INSERT или REPLACE, но указывает все поля, используя встроенные предложения SELECT для получения текущего значения для полей, которые вы не хотите изменять.


Я думаю, стоит отметить, что здесь может быть какое-то неожиданное поведение, если вы не до конца понимаете, как ПЕРВИЧНЫЙ КЛЮЧ и уникальный взаимодействовать.

в качестве примера, если вы хотите вставить запись, только если имя поле в настоящее время не занято, и если это так, вы хотите, чтобы исключение ограничения срабатывало, чтобы сообщить вам, то ВСТАВИТЬ ИЛИ ЗАМЕНИТЬ не будет бросать и исключение, а вместо этого разрешит уникальный само ограничение путем замены конфликтующей записи (существующей записи с тем же имя). Гаспар демонстрирует это очень хорошо в ответ выше.

Если вы хотите, чтобы исключение ограничения срабатывало, вы должны использовать вставить заявление, и полагаться на отдельной обновление команда для обновления записи, как только вы знаете, что имя не принято.