Declaración "Insertar si no existe" en SQLite

143

Tengo una base de datos SQLite. Estoy tratando de insertar valores ( users_id, lessoninfo_id) en la tabla bookmarks, solo si ambos no existen antes en una fila.

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

Esto da un error que dice:

error db cerca de donde la sintaxis.

usuario2780638
fuente

Respuestas:

138

Si tiene una tabla llamada notas que tiene dos columnas idy textdebería poder hacer esto:

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

Si un registro ya contiene una fila donde textes igual a 'texto para insertar' y ides igual a 5, entonces la operación de inserción será ignorada.

No sé si esto funcionará para su consulta particular, pero tal vez le dé una pista sobre cómo proceder.

Le aconsejaría que en su lugar diseñe su tabla para que no se permitan duplicados como se explica a @CLs answercontinuación.

Código ciclónico
fuente
436

Si nunca desea tener duplicados, debe declarar esto como una restricción de tabla:

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

(Una clave principal sobre ambas columnas tendría el mismo efecto).

Entonces es posible decirle a la base de datos que desea ignorar silenciosamente los registros que violarían dicha restricción :

INSERT OR IGNORE INTO bookmarks(users_id, lessoninfo_id) VALUES(123, 456)
CL.
fuente
12
¿Cuál es la forma óptima de obtener la ID de la fila recién insertada o la ya existente, para poder insertarla en otra tabla que tenga una clave externa para esta? Por ejemplo, tengo dos tablas person (id, name unique)y cat (person_id, name unique)quiero insertar muchos pares (person_name, cat_name).
Aur Saraf
2
La lectura de la ID de una fila existente solo es posible con una consulta SELECT. Pero esta es una pregunta diferente.
CL.
1
Tal vez añadiendo ON CONFLICT IGNOREa CREATE TABLEque sería un poco más manejable
defhlt
1
@ rightaway717 "Ignorar" significa que no pasa nada; Esta pregunta no tiene nada que ver con la actualización.
CL.
1
@ Hack06 Android insert () se comporta de manera diferente; debe reemplazarlo con insertOrThrow () o insertWithOnConflict () .
CL.
21

Para una columna única, use esto:

INSERT OR REPLACE INTO table () values();

Para obtener más información, consulte: sqlite.org/lang_insert

Ali Bagheri
fuente
Esto no funciona para mi. siempre se inserta como en insertar o reemplazar en los valores de my_table (col1, col2) ('1', '2'); agregará varias filas de 1 2
Peter Moore
Podría agregar que funciona bien si se establece la restricción Unique(col1,col2)y también tiene col3, porque una inserción o ignorar fallaría cuando esto actualice col3 al nuevo valor. insert or replace into my_table values('1','2','5')reemplaza una fila'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 es la forma más rápida.

Para algunos otros motores SQL, puede usar una tabla ficticia que contenga 1 registro. p.ej:

select 1, 167 from ONE_RECORD_DUMMY_TABLE
suat dmk
fuente