Restrição de tabela SQLite - exclusiva em várias colunas

179

Posso encontrar "gráficos" de sintaxe neste site do SQLite, mas nenhum exemplo e meu código está travando. Eu tenho outras tabelas com restrições exclusivas em uma única coluna, mas quero adicionar uma restrição à tabela em duas colunas. É isso que eu tenho que está causando uma SQLiteException com a mensagem "erro de sintaxe".

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

Estou fazendo isso com base no seguinte:

restrição de tabela

Para ficar claro, a documentação no link que forneci diz que CONTSTRAINT namedeve vir antes da minha definição de restrição.

Algo que pode levar à solução, porém, é que tudo o que segue minhas definições de coluna entre parênteses é o que o depurador reclama.

Se eu colocar

...last_column_name last_col_datatype) CONSTRAINT ...

o erro está próximo de "CONSTRAINT": erro de sintaxe

Se eu colocar

...last_column_name last_col_datatype) UNIQUE ...

o erro está próximo de "UNIQUE": erro de sintaxe

Rico
fonte
1
UNIQUE está faltando uma vírgula antes de começar ..
Majid Bashir 29/11

Respostas:

345

Coloque a declaração UNIQUE na seção de definição de coluna; exemplo de trabalho:

CREATE TABLE a (
    i INT,
    j INT,
    UNIQUE(i, j) ON CONFLICT REPLACE
);
Ayman Hourieh
fonte
6
Boa resposta +1. Essa sintaxe de criação permite que eu use o método de inserção regular, e não o insertWithOnConflict com o sinalizador SQLiteDatabase.CONFLICT_REPLACE?
Oleg Belousov
3
Estou usando ON CONFLICT IGNORE(ainda não tentei substituir) com mais de duas colunas, mas não estou vendo isso respeitar a restrição exclusiva, apenas adiciona alegremente as duplicatas.
Michael
5
aparentemente porque eu tenho colunas nulas, e que apenas dispara o único check-out pela janela #
Michael Michael
Cuidado ao usá- ON CONFLICT REPLACElo pode não ser o que você deseja - ele exclui linhas pré-existentes para permitir que a nova linha seja inserida. Normalmente, eu gostaria de abortar ou descolar a violação de restrição. Cláusula SQLite ON CONFLICT
karmakaze 23/02
9

Bem, sua sintaxe não corresponde ao link que você incluiu, que especifica:

 CREATE TABLE name (column defs) 
    CONSTRAINT constraint_name    -- This is new
    UNIQUE (col_name1, col_name2) ON CONFLICT REPLACE
Larry Lustig
fonte
Inicialmente fiz isso ... não funcionou. Eu tentei novamente apenas no caso ... ainda não funciona
rico
1

Cuidado ao definir a tabela, pois você obterá resultados diferentes ao inserir. Considere o seguinte



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> 

Embora o efeito de inserção / atualização seja o mesmo, as idalterações baseadas no tipo de definição da tabela (consulte a segunda tabela em que 'Alice' agora possui id = 4; a primeira tabela está fazendo mais do que eu espero que ela faça, mantenha a PRIMARY KEY na mesma ) Esteja ciente deste efeito.

punkish
fonte
1

Se você já possui uma tabela e não pode / não deseja recriá-la por qualquer motivo, use índices :

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