Оператор «Вставить, если не существует» в SQLite


152

У меня есть база данных SQLite. Я пытаюсь вставить значения ( users_id, lessoninfo_id) в таблицу bookmarks, только если оба ранее не существовали в строке.

INSERT INTO bookmarks(users_id,lessoninfo_id) 
VALUES(
    (SELECT _id FROM Users WHERE User='"+$('#user_lesson').html()+"'),
        (SELECT _id FROM lessoninfo 
        WHERE Lesson="+lesson_no+" AND cast(starttime AS int)="+Math.floor(result_set.rows.item(markerCount-1).starttime)+") 
        WHERE NOT EXISTS (
            SELECT users_id,lessoninfo_id from bookmarks 
            WHERE users_id=(SELECT _id FROM Users 
            WHERE User='"+$('#user_lesson').html()+"') AND lessoninfo_id=(
                SELECT _id FROM lessoninfo
                WHERE Lesson="+lesson_no+")))

Это дает сообщение об ошибке:

db ошибка рядом с синтаксисом.

Ответы:


150

Если у вас есть таблица с двумя столбцами, называемая заметками, idи textвы можете сделать это следующим образом:

INSERT INTO memos(id,text) 
SELECT 5, 'text to insert' 
WHERE NOT EXISTS(SELECT 1 FROM memos WHERE id = 5 AND text = 'text to insert');

Если запись уже содержит строку, textравную «текст для вставки» и idравную 5, то операция вставки будет проигнорирована.

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

Я бы посоветовал вам вместо этого спроектировать свою таблицу так, чтобы не допускались дублирования, как описано @CLs answerниже.


454

Если вы никогда не хотите иметь дубликаты, вы должны объявить это как ограничение таблицы:

CREATE TABLE bookmarks(
    users_id INTEGER,
    lessoninfo_id INTEGER,
    UNIQUE(users_id, lessoninfo_id)
);

(Первичный ключ для обоих столбцов будет иметь тот же эффект.)

Затем можно указать базе данных, что вы хотите молча игнорировать записи, которые нарушили бы такое ограничение :

INSERT OR IGNORE INTO bookmarks(users_id, lessoninfo_id) VALUES(123, 456)

15
Каков оптимальный способ получить идентификатор только что вставленной строки или уже существующей, чтобы я мог вставить ее в другую таблицу, у которой есть внешний ключ к этой? например, у меня есть две таблицы, person (id, name unique)и cat (person_id, name unique)я хочу вставить много пар (person_name, cat_name)?
Aur Saraf

2
Считывание идентификатора существующей строки возможно только с помощью запроса SELECT. Но это другой вопрос.
кл.

1
Возможно, добавление ON CONFLICT IGNOREк CREATE TABLEбыло бы немного
удобнее

1
@ rightaway717 «Игнорировать» означает, что ничего не происходит; этот вопрос не имеет ничего общего с обновлением.
кл.

1
@ Hack06 Android-функция insert () ведет себя иначе; вы должны заменить его на insertOrThrow () или insertWithOnConflict () .
кл.

29

Для уникального столбца используйте это:

INSERT OR REPLACE INTO table () values();

Для получения дополнительной информации см .: sqlite.org/lang_insert


У меня это не работает. он всегда вставляет как в вставке или замене в значения my_table (col1, col2) ('1', '2'); добавит несколько строк по 1 2
Питер Мур

Я мог бы добавить, что он работает хорошо, если установлено ограничение Unique(col1,col2)и у вас также есть col3, потому что вставка или игнорирование не сработает, когда это обновит col3 до нового значения. insert or replace into my_table values('1','2','5')заменяет ряд'1','2','3'
Питер Мур

4
insert into bookmarks (users_id, lessoninfo_id)

select 1, 167
EXCEPT
select user_id, lessoninfo_id
from bookmarks
where user_id=1
and lessoninfo_id=167;

Это самый быстрый способ.

Для некоторых других механизмов SQL вы можете использовать фиктивную таблицу, содержащую 1 запись. например:

select 1, 167 from ONE_RECORD_DUMMY_TABLE
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.