Anweisung "Einfügen, wenn nicht vorhanden" in SQLite

140

Ich habe eine SQLite-Datenbank. Ich versuche, Werte ( users_id, lessoninfo_id) in die Tabelle einzufügen bookmarks, nur wenn beide vorher nicht in einer Zeile existieren.

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

Dies gibt einen Fehler aus, der besagt:

DB-Fehler in der Nähe der Syntax.

user2780638
quelle

Antworten:

135

Wenn Sie eine Tabelle mit dem Namen Memo haben , die zwei Spalten haben idund textSie sollen wie dies zu tun in der Lage:

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

Wenn ein Datensatz bereits eine Zeile enthält, die textgleich "einzufügender Text" und idgleich 5 ist, wird der Einfügevorgang ignoriert.

Ich weiß nicht, ob dies für Ihre spezielle Abfrage funktioniert, aber vielleicht gibt es Ihnen einen Hinweis, wie Sie vorgehen sollen.

Ich würde empfehlen, dass Sie stattdessen Ihre Tabelle so gestalten, dass keine Duplikate zulässig sind, wie @CLs answerunten erläutert .

Cyclonecode
quelle
435

Wenn Sie niemals Duplikate haben möchten, sollten Sie dies als Tabelleneinschränkung deklarieren:

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

(Ein Primärschlüssel über beiden Spalten hätte den gleichen Effekt.)

Es ist dann möglich, der Datenbank mitzuteilen, dass Sie Datensätze, die eine solche Einschränkung verletzen würden , stillschweigend ignorieren möchten :

INSERT OR IGNORE INTO bookmarks(users_id, lessoninfo_id) VALUES(123, 456)
CL.
quelle
12
Was ist der optimale Weg, um dann die ID der neu eingefügten oder der bereits vorhandenen Zeile zu erhalten, damit ich sie in eine andere Tabelle einfügen kann, die einen Fremdschlüssel für diese hat? zB habe ich zwei Tabellen person (id, name unique)und cat (person_id, name unique)möchte viele Paare einfügen (person_name, cat_name)?
Aur Saraf
2
Das Lesen der ID einer vorhandenen Zeile ist nur mit einer SELECT-Abfrage möglich. Dies ist jedoch eine andere Frage.
CL.
1
Vielleicht wäre das Hinzufügen ON CONFLICT IGNOREzu CREATE TABLEetwas praktischer
defhlt
1
@ rightaway717 "Ignorieren" bedeutet, dass nichts passiert; Diese Frage hat nichts mit Aktualisierung zu tun.
CL.
1
@ Hack06 Android insert () verhält sich anders; Sie sollten es durch insertOrThrow () oder insertWithOnConflict () ersetzen .
CL.
21

Verwenden Sie für eine eindeutige Spalte Folgendes:

INSERT OR REPLACE INTO table () values();

Weitere Informationen finden Sie unter: sqlite.org/lang_insert

Ali Bagheri
quelle
Das funktioniert bei mir nicht. es wird immer wie beim Einfügen oder Ersetzen in my_table (col1, col2) -Werte ('1', '2') eingefügt; wird mehrere Zeilen von 1 2 hinzufügen
Peter Moore
Ich könnte hinzufügen, dass es gut funktioniert, wenn die Einschränkung eingerichtet ist Unique(col1,col2)und Sie auch col3 haben, da ein Einfügen oder Ignorieren fehlschlagen würde, wenn dadurch col3 auf den neuen Wert aktualisiert wird. insert or replace into my_table values('1','2','5')ersetzt eine Reihe'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;

Dies ist der schnellste Weg.

Für einige andere SQL-Engines können Sie eine Dummy-Tabelle verwenden, die 1 Datensatz enthält. z.B:

select 1, 167 from ONE_RECORD_DUMMY_TABLE
suat dmk
quelle