У SQLite оператор «Вставити, якщо його немає»


143

У мене є база даних 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 помилка поблизу синтаксису.

Відповіді:


138

Якщо у вас є таблиця під назвою пам'ятки, яка має два стовпці, 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нижче.


436

Якщо ви ніколи не хочете мати дублікатів, вам слід оголосити це обмеженням таблиці:

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)

12
Який оптимальний спосіб отримати ідентифікатор щойно вставленого рядка або вже наявного, щоб я міг вставити його в іншу таблицю, яка має зовнішній ключ до цього? наприклад, у мене є дві таблиці, 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 () поводиться по-різному; слід замінити його на insertOrThrow () або insertWithOnConflict () .
ЗР.

21

Для унікального стовпця використовуйте це:

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 можна використовувати таблицю Dummy, що містить 1 запис. наприклад:

select 1, 167 from ONE_RECORD_DUMMY_TABLE
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.