Restricción de tabla SQLite: exclusiva en varias columnas

179

Puedo encontrar "gráficos" de sintaxis en esto en el sitio web de SQLite, pero no hay ejemplos y mi código falla. Tengo otras tablas con restricciones únicas en una sola columna, pero quiero agregar una restricción a la tabla en dos columnas. Esto es lo que tengo que está causando una SQLiteException con el mensaje "error de sintaxis".

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

Estoy haciendo esto basado en lo siguiente:

restricción de tabla

Para ser claros, la documentación en el enlace que proporcioné dice que CONTSTRAINT namedebería venir antes de mi definición de restricción.

Sin embargo, algo que puede conducir a la solución es que lo que sigue a mis definiciones de columna entre paréntesis es de lo que se queja el depurador.

Si pongo

...last_column_name last_col_datatype) CONSTRAINT ...

el error está cerca de "CONSTRAINT": error de sintaxis

Si pongo

...last_column_name last_col_datatype) UNIQUE ...

el error está cerca de "ÚNICO": error de sintaxis

Rico
fuente
1
ÚNICO falta una coma antes de que comience ..
Majid Bashir

Respuestas:

345

Ponga la declaración ÚNICA dentro de la sección de definición de columna; ejemplo de trabajo:

CREATE TABLE a (
    i INT,
    j INT,
    UNIQUE(i, j) ON CONFLICT REPLACE
);
Ayman Hourieh
fuente
66
Buena respuesta +1. ¿Esta sintaxis de creación me permite usar el método de inserción regular y no el insertWithOnConflict con el indicador SQLiteDatabase.CONFLICT_REPLACE?
Oleg Belousov
3
Estoy usando ON CONFLICT IGNORE(no he intentado reemplazar aún) con más de 2 columnas, pero no veo que cumpla con la restricción única, solo agrega alegremente los duplicados.
Michael
55
aparentemente porque tengo columnas NULL, y eso solo dispara el cheque único por la ventana
Michael
Tenga cuidado de que usarlo ON CONFLICT REPLACEno sea lo que desea: elimina las filas preexistentes para permitir que se inserte la nueva fila. Normalmente, me gustaría ABORTAR o ROLLBACK la violación de restricción. Cláusula SQLite EN CONFLICTO
karmakaze
9

Bueno, su sintaxis no coincide con el enlace que incluyó, que especifica:

 CREATE TABLE name (column defs) 
    CONSTRAINT constraint_name    -- This is new
    UNIQUE (col_name1, col_name2) ON CONFLICT REPLACE
Larry Lustig
fuente
Inicialmente hice eso ... no funcionó. Lo intenté de nuevo por si acaso ... todavía no funciona
Rich
1

Tenga cuidado al definir la tabla para obtener diferentes resultados al insertar. Considera lo siguiente



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> 

Si bien el efecto de inserción / actualización es el mismo, los idcambios se basan en el tipo de definición de la tabla (vea la segunda tabla donde ahora tiene 'Alice' id = 4; la primera tabla está haciendo más de lo que espero que haga, mantenga la LLAVE PRIMARIA igual) ) Tenga en cuenta este efecto.

punkish
fuente
1

Si ya tiene una tabla y no puede / no desea volver a crearla por cualquier razón, use índices :

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