SQLite-Tabelleneinschränkung - eindeutig für mehrere Spalten

179

Ich kann Syntax "Diagramme" auf der SQLite-Website finden, aber keine Beispiele und mein Code stürzt ab. Ich habe andere Tabellen mit eindeutigen Einschränkungen für eine einzelne Spalte, möchte jedoch der Tabelle für zwei Spalten eine Einschränkung hinzufügen. Dies ist, was ich habe, das eine SQLiteException mit der Meldung "Syntaxfehler" verursacht.

CREATE TABLE name (column defs) 
UNIQUE (col_name1, col_name2) ON CONFLICT REPLACE

Ich mache das basierend auf folgendem:

Tabellenbeschränkung

In der Dokumentation zu dem von mir bereitgestellten Link heißt es, dass dies CONTSTRAINT namevor meiner Einschränkungsdefinition erfolgen sollte.

Was jedoch zur Lösung führen kann, ist, dass sich der Debugger über alles beschwert, was meinen Spaltendefinitionen in Klammern folgt.

Wenn ich setze

...last_column_name last_col_datatype) CONSTRAINT ...

Der Fehler liegt in der Nähe von "CONSTRAINT": Syntaxfehler

Wenn ich setze

...last_column_name last_col_datatype) UNIQUE ...

Der Fehler liegt in der Nähe von "UNIQUE": Syntaxfehler

Reich
quelle
1
EINZIGARTIG fehlt ein Komma, bevor es beginnt.
Majid Bashir

Antworten:

344

Fügen Sie die UNIQUE-Deklaration in den Abschnitt zur Spaltendefinition ein. Arbeitsbeispiel:

CREATE TABLE a (
    i INT,
    j INT,
    UNIQUE(i, j) ON CONFLICT REPLACE
);
Ayman Hourieh
quelle
6
Schöne Antwort +1. Ermöglicht mir diese Erstellungssyntax die Verwendung der regulären Einfügemethode und nicht die Methode insertWithOnConflict mit dem Flag SQLiteDatabase.CONFLICT_REPLACE?
Oleg Belousov
3
Ich verwende ON CONFLICT IGNORE(habe noch nicht versucht, es zu ersetzen) mit mehr als 2 Spalten, aber ich sehe nicht, dass es die eindeutige Einschränkung berücksichtigt, sondern nur fröhlich die Duplikate hinzufügt.
Michael
5
anscheinend, weil ich NULL-Spalten habe, und das schießt nur den einzigartigen Check aus dem Fenster
Michael
Beachten Sie, dass die Verwendung ON CONFLICT REPLACEmöglicherweise nicht Ihren Wünschen entspricht. Sie löscht bereits vorhandene Zeilen, damit die neue Zeile eingefügt werden kann. Normalerweise möchte ich die Einschränkungsverletzung abbrechen oder zurückrollen. SQLite ON CONFLICT-Klausel
karmakaze
9

Nun, Ihre Syntax stimmt nicht mit dem von Ihnen angegebenen Link überein, der Folgendes angibt:

 CREATE TABLE name (column defs) 
    CONSTRAINT constraint_name    -- This is new
    UNIQUE (col_name1, col_name2) ON CONFLICT REPLACE
Larry Lustig
quelle
Ich habe das anfangs gemacht ... hat nicht funktioniert. Ich habe es noch einmal versucht, nur für den Fall ... funktioniert immer noch nicht
Rich
1

Achten Sie darauf, wie Sie die Tabelle definieren, da Sie beim Einfügen unterschiedliche Ergebnisse erhalten. Folgendes berücksichtigen



CREATE TABLE IF NOT EXISTS t1 (id INTEGER PRIMARY KEY, a TEXT UNIQUE, b TEXT);
INSERT INTO t1 (a, b) VALUES
    ('Alice', 'Some title'),
    ('Bob', 'Palindromic guy'),
    ('Charles', 'chucky cheese'),
    ('Alice', 'Some other title') 
    ON CONFLICT(a) DO UPDATE SET b=excluded.b;
CREATE TABLE IF NOT EXISTS t2 (id INTEGER PRIMARY KEY, a TEXT UNIQUE, b TEXT, UNIQUE(a) ON CONFLICT REPLACE);
INSERT INTO t2 (a, b) VALUES
    ('Alice', 'Some title'),
    ('Bob', 'Palindromic guy'),
    ('Charles', 'chucky cheese'),
    ('Alice', 'Some other title');

$ sqlite3 test.sqlite
SQLite version 3.28.0 2019-04-16 19:49:53
Enter ".help" for usage hints.
sqlite> CREATE TABLE IF NOT EXISTS t1 (id INTEGER PRIMARY KEY, a TEXT UNIQUE, b TEXT);
sqlite> INSERT INTO t1 (a, b) VALUES
   ...>     ('Alice', 'Some title'),
   ...>     ('Bob', 'Palindromic guy'),
   ...>     ('Charles', 'chucky cheese'),
   ...>     ('Alice', 'Some other title') 
   ...>     ON CONFLICT(a) DO UPDATE SET b=excluded.b;
sqlite> CREATE TABLE IF NOT EXISTS t2 (id INTEGER PRIMARY KEY, a TEXT UNIQUE, b TEXT, UNIQUE(a) ON CONFLICT REPLACE);
sqlite> INSERT INTO t2 (a, b) VALUES
   ...>     ('Alice', 'Some title'),
   ...>     ('Bob', 'Palindromic guy'),
   ...>     ('Charles', 'chucky cheese'),
   ...>     ('Alice', 'Some other title');
sqlite> .mode col
sqlite> .headers on
sqlite> select * from t1;
id          a           b               
----------  ----------  ----------------
1           Alice       Some other title
2           Bob         Palindromic guy 
3           Charles     chucky cheese   
sqlite> select * from t2;
id          a           b              
----------  ----------  ---------------
2           Bob         Palindromic guy
3           Charles     chucky cheese  
4           Alice       Some other titl
sqlite> 

Während der Einfüge- / Aktualisierungseffekt derselbe ist , bleiben die idÄnderungen basierend auf dem Tabellendefinitionstyp (siehe die zweite Tabelle, in der 'Alice' jetzt vorhanden ist id = 4; die erste Tabelle macht mehr von dem, was ich von ihr erwarte, den PRIMARY KEY gleich ). Seien Sie sich dieses Effekts bewusst.

punkig
quelle
1

Wenn Sie bereits eine Tabelle haben und diese aus irgendeinem Grund nicht neu erstellen können / wollen, verwenden Sie Indizes :

CREATE UNIQUE INDEX my_index ON my_table(col_1, col_2);
Oleg Yablokov
quelle