Ograniczenie tabeli SQLite - unikalne dla wielu kolumn

179

Na tej stronie internetowej SQLite mogę znaleźć „wykresy” składniowe, ale nie ma żadnych przykładów, a mój kod ulega awarii. Mam inne tabele z unikalnymi ograniczeniami w jednej kolumnie, ale chcę dodać ograniczenie do tabeli w dwóch kolumnach. To, co mam, powoduje SQLiteException z komunikatem „błąd składni”.

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

Robię to na podstawie:

ograniczenie tabeli

Aby wyjaśnić, w dokumentacji podanego przeze mnie linku jest napisane, że CONTSTRAINT namepowinien on znajdować się przed moją definicją ograniczenia.

Jednak rozwiązaniem może być to, że cokolwiek wynika z moich nawiasowych definicji kolumn, na co narzeka debugger.

Jeśli tak

...last_column_name last_col_datatype) CONSTRAINT ...

błąd jest bliski „CONSTRAINT”: błąd składni

Jeśli tak

...last_column_name last_col_datatype) UNIQUE ...

błąd jest bliski „UNIQUE”: błąd składni

Bogaty
źródło
1
UNIQUE nie ma przecinka, zanim się zacznie.
Majid Bashir

Odpowiedzi:

345

Umieść deklarację UNIQUE w sekcji definicji kolumny; przykład roboczy:

CREATE TABLE a (
    i INT,
    j INT,
    UNIQUE(i, j) ON CONFLICT REPLACE
);
Ayman Hourieh
źródło
6
Dobra odpowiedź +1. Czy ta składnia pozwala mi używać zwykłej metody wstawiania, a nie metody insertWithOnConflict z flagą SQLiteDatabase.CONFLICT_REPLACE?
Oleg Belousov
3
Używam ON CONFLICT IGNORE(jeszcze nie próbowałem zastąpić) z więcej niż 2 kolumnami, ale nie widzę, aby honorowało to wyjątkowe ograniczenie, po prostu wesoło dodaje duplikaty.
Michael
5
najwyraźniej ponieważ mam kolumny NULL, a to po prostu strzela do unikalnego okna
Michael
Uwaga: używanie ON CONFLICT REPLACEgo może nie być tym, czego chcesz - usuwa istniejące wcześniej wiersze, aby umożliwić wstawienie nowego wiersza. Zwykle chciałbym ABORT lub ROLLBACK naruszenie ograniczenia. Klauzula SQLite ON CONFLICT
karmakaze
9

Cóż, twoja składnia nie pasuje do dołączonego linku, który określa:

 CREATE TABLE name (column defs) 
    CONSTRAINT constraint_name    -- This is new
    UNIQUE (col_name1, col_name2) ON CONFLICT REPLACE
Larry Lustig
źródło
Początkowo to robiłem ... nie działało. Próbowałem jeszcze raz, na wszelki wypadek ... nadal nie działa
Rich
1

Uważaj, jak zdefiniujesz tabelę, ponieważ uzyskasz różne wyniki przy wstawianiu. Rozważ następujące



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> 

Podczas gdy efekt wstawiania / aktualizacji jest taki sam, idzmiany oparte na typie definicji tabeli (patrz druga tabela, w której teraz ma „Alice” id = 4; pierwsza tabela robi więcej, niż się spodziewam, zachowaj KLUCZ PODSTAWOWY taki sam ). Bądź świadomy tego efektu.

punkowy
źródło
1

Jeśli masz już tabelę i nie możesz / nie chcesz jej ponownie utworzyć z jakiegokolwiek powodu, użyj indeksów :

CREATE UNIQUE INDEX my_index ON my_table(col_1, col_2);
Oleg Jabłokow
źródło