Vincolo di tabella SQLite: univoco su più colonne


179

Posso trovare "grafici" di sintassi su questo sul sito Web di SQLite, ma nessun esempio e il mio codice si blocca. Ho altre tabelle con vincoli univoci su una singola colonna, ma voglio aggiungere un vincolo alla tabella su due colonne. Questo è ciò che ho che sta causando una SQLiteException con il messaggio "errore di sintassi".

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

Lo sto facendo in base a quanto segue:

table-constraint

Per essere chiari, la documentazione sul link che ho fornito dice che CONTSTRAINT namedovrebbe venire prima della mia definizione di vincolo.

Qualcosa che può portare alla soluzione è che ciò che segue le definizioni delle mie colonne tra parentesi è ciò di cui si lamenta il debugger.

Se lo metto

...last_column_name last_col_datatype) CONSTRAINT ...

l'errore è vicino a "VINCITORE": errore di sintassi

Se lo metto

...last_column_name last_col_datatype) UNIQUE ...

l'errore è vicino a "UNIQUE": errore di sintassi


1
UNICA manca una virgola prima che inizi ..
Majid Bashir,

Risposte:


345

Inserire la dichiarazione UNIQUE nella sezione di definizione della colonna; esempio funzionante:

CREATE TABLE a (
    i INT,
    j INT,
    UNIQUE(i, j) ON CONFLICT REPLACE
);

6
Bella risposta +1. Questa sintassi di creazione mi consente di utilizzare il metodo di inserimento normale e non l'insertWithOnConflict con il flag SQLiteDatabase.CONFLICT_REPLACE?
Oleg Belousov,

3
Sto usando ON CONFLICT IGNORE(non ho ancora provato a sostituire) con più di 2 colonne, ma non lo vedo onorare il vincolo unico, aggiunge semplicemente allegramente i duplicati.
Michael,

5
apparentemente perché ho le colonne NULL, e questo spara alla check out unica dalla finestra
Michael

Attenzione ON CONFLICT REPLACE, potrebbe non essere quello che desideri: elimina le righe preesistenti per consentire l'inserimento della nuova riga. Normalmente, vorrei ABORTARE o ROLLBACK la violazione del vincolo. Clausola SQLite ON CONFLICT
karmakaze

9

Bene, la tua sintassi non corrisponde al link che hai incluso, che specifica:

 CREATE TABLE name (column defs) 
    CONSTRAINT constraint_name    -- This is new
    UNIQUE (col_name1, col_name2) ON CONFLICT REPLACE

Inizialmente l'ho fatto ... non ha funzionato. L'ho provato di nuovo nel caso in cui ... non funziona ancora
Rich

1

Fai attenzione a come definisci la tabella per ottenere risultati diversi all'inserimento. Considera quanto segue



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> 

Mentre l'effetto insert / update è lo stesso, le idmodifiche si basano sul tipo di definizione della tabella (vedere la seconda tabella in cui è ora presente 'Alice' id = 4; la prima tabella sta facendo più di quello che mi aspetto che faccia, mantieni lo stesso PRIMARY KEY ). Sii consapevole di questo effetto.


1

Se hai già una tabella e non puoi / non vuoi ricrearla per qualsiasi motivo, usa gli indici :

CREATE UNIQUE INDEX my_index ON my_table(col_1, col_2);
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.