Istruzione "Inserisci se non esiste" in SQLite


143

Ho un database SQLite. Sto cercando di inserire valori ( users_id, lessoninfo_id) nella tabella bookmarks, solo se entrambi non esistono prima in una riga.

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

Questo dà un errore che dice:

errore db vicino a dove sintassi.

Risposte:


138

Se hai una tabella chiamata memo con due colonne ide textdovresti essere in grado di fare così:

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 un record contiene già una riga in cui textè uguale a "testo da inserire" ed idè uguale a 5, l'operazione di inserimento verrà ignorata.

Non so se questo funzionerà per la tua query particolare, ma forse ti darà un suggerimento su come procedere.

Vorrei consigliare invece di progettare la tabella in modo che non siano consentiti duplicati, come spiegato di @CLs answerseguito.


436

Se non si desidera mai avere duplicati, è necessario dichiararlo come vincolo di tabella:

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

(Una chiave primaria su entrambe le colonne avrebbe lo stesso effetto.)

È quindi possibile dire al database che si desidera ignorare silenziosamente i record che violerebbero tale vincolo :

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

12
Qual è il modo ottimale per ottenere quindi l'ID della riga appena inserita o di quella già esistente, così posso inserirla in un'altra tabella che ha una chiave esterna per questa? ad es. ho due tabelle person (id, name unique)e cat (person_id, name unique)voglio inserire molte coppie (person_name, cat_name)?
Aur Saraf,

2
La lettura dell'ID di una riga esistente è possibile solo con una query SELECT. Ma questa è una domanda diversa.
CL.

1
Forse aggiungere ON CONFLICT IGNOREa CREATE TABLEsarebbe un po 'più utile
defhlt

1
@ rightaway717 "Ignora" significa che non accade nulla; questa domanda non ha nulla a che fare con l'aggiornamento.
CL.

1
@ Hack06 L'inserto () di Android si comporta diversamente; dovresti sostituirlo con insertOrThrow () o insertWithOnConflict () .
CL.

21

Per una colonna univoca, utilizzare questo:

INSERT OR REPLACE INTO table () values();

Per ulteriori informazioni, consultare: sqlite.org/lang_insert


Questo non funziona per me. si inserisce sempre come in insert o sostituisce nei valori my_table (col1, col2) ('1', '2'); aggiungerà più righe di 1 2
Peter Moore,

Potrei aggiungere che funziona bene se il vincolo viene messo in atto Unique(col1,col2)e hai anche col3, perché un inserimento o un'ignorare fallirebbe dove questo aggiornerà col3 al nuovo valore. insert or replace into my_table values('1','2','5')sostituisce una riga'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;

Questo è il modo più veloce.

Per alcuni altri motori SQL, è possibile utilizzare una tabella fittizia contenente 1 record. per esempio:

select 1, 167 from ONE_RECORD_DUMMY_TABLE
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.