Instrução "Inserir se não existir" no SQLite

142

Eu tenho um banco de dados SQLite. Estou tentando inserir valores ( users_id, lessoninfo_id) na tabela bookmarks, apenas se ambos não existirem antes em uma linha.

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+")))

Isso gera um erro dizendo:

erro db perto de onde sintaxe.

user2780638
fonte

Respostas:

138

Se você possui uma tabela chamada memorandos que possui duas colunas ide textdeve poder fazer o seguinte:

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');

Se um registro já contiver uma linha textigual a 'texto a inserir' e idigual a 5, a operação de inserção será ignorada.

Não sei se isso funcionará para sua consulta específica, mas talvez ele lhe dê uma dica sobre como proceder.

Eu aconselho que você crie sua tabela para que não sejam permitidas duplicatas, conforme explicado @CLs answerabaixo.

Cyclonecode
fonte
435

Se você nunca quiser duplicar, declare isso como uma restrição de tabela:

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

(Uma chave primária sobre as duas colunas teria o mesmo efeito.)

É então possível dizer ao banco de dados que você deseja ignorar silenciosamente os registros que violariam tal restrição :

INSERT OR IGNORE INTO bookmarks(users_id, lessoninfo_id) VALUES(123, 456)
CL.
fonte
12
Qual é a maneira ideal de obter o ID da linha recém-inserida ou da já existente, para que eu possa inseri-la em outra tabela que possua uma chave estrangeira? por exemplo, eu tenho duas tabelas person (id, name unique)e cat (person_id, name unique)quero inserir muitos pares (person_name, cat_name)?
Aur Saraf 23/02
2
A leitura do ID de uma linha existente é possível apenas com uma consulta SELECT. Mas esta é uma pergunta diferente.
CL.
1
Talvez adicionando ON CONFLICT IGNOREa CREATE TABLEseria um prático pouco mais
defhlt
1
@ rightaway717 "Ignorar" significa que nada acontece; Esta questão não tem nada a ver com atualização.
CL.
1
@ Hack06 O insert () do Android se comporta de maneira diferente; você deve substituí-lo por insertOrThrow () ou insertWithOnConflict () .
CL.
21

Para uma coluna exclusiva, use este:

INSERT OR REPLACE INTO table () values();

Para mais informações, consulte: sqlite.org/lang_insert

Ali Bagheri
fonte
Isso não funciona para mim. ele sempre insere como em inserir ou substituir em valores minha_tabela (col1, col2) ('1', '2'); adicionará várias linhas de 1 2
Peter Moore
Devo acrescentar que funcionará bem se a restrição for colocada no lugar Unique(col1,col2)e você também tiver o col3, porque uma inserção ou ignorar falhará onde isso atualizará o col3 para o novo valor. insert or replace into my_table values('1','2','5')substitui uma linha'1','2','3'
Peter Moore
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;

Esta é a maneira mais rápida.

Para alguns outros mecanismos SQL, você pode usar uma tabela Dummy contendo 1 registro. por exemplo:

select 1, 167 from ONE_RECORD_DUMMY_TABLE
suat dmk
fonte