SQLite 表约束 - 在多个列上唯一

Posted

技术标签:

【中文标题】SQLite 表约束 - 在多个列上唯一【英文标题】:SQLite table constraint - unique on multiple columns 【发布时间】:2011-02-11 17:06:21 【问题描述】:

我可以在 SQLite 网站上找到语法“图表”,但没有示例,我的代码崩溃了。我有其他表在单个列上具有唯一约束,但我想在两列上的表中添加约束。这就是我所拥有的导致 SQLiteException 消息“语法错误”的原因。

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

我这样做是基于以下几点:

table-constraint

为了清楚起见,我提供的链接上的文档说 CONTSTRAINT name 应该在我的约束定义之前。

不过,可能导致解决方案的事情是,我带括号的列定义后面的任何内容都是调试器所抱怨的。

如果我放了

...last_column_name last_col_datatype) CONSTRAINT ...

错误是在“CONSTRAINT”附近:语法错误

如果我放了

...last_column_name last_col_datatype) UNIQUE ...

错误是在“UNIQUE”附近:语法错误

【问题讨论】:

UNIQUE 在开始前缺少一个逗号.. 【参考方案1】:

将 UNIQUE 声明放在列定义部分;工作示例:

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

【讨论】:

不错的答案+1。这种创建语法是否允许我使用常规插入方法,而不是带有 SQLiteDatabase.CONFLICT_REPLACE 标志的 insertWithOnConflict? 我正在使用超过 2 列的 ON CONFLICT IGNORE(尚未尝试替换),但我没有看到它遵守唯一约束,它只是愉快地添加了重复项。跨度> 显然是因为我有 NULL 列,这只是拍摄了独特的检查窗口 小心使用ON CONFLICT REPLACE 它可能不是你想要的——它会删除预先存在的行以允许插入新行。通常,我想 ABORT 或 ROLLBACK 违反约束。 SQLite ON CONFLICT clause 似乎在android上完全忽略了在create语句中添加UNIQUE(i, j)。它创建表,但不使用 UNIQUE 约束。我只能通过使用索引来做到这一点。【参考方案2】:

好吧,您的语法与您包含的链接不匹配,该链接指定:

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

【讨论】:

我最初是这样做的……没有用。我又试了一次以防万一……还是不行【参考方案3】:

如果您已经有一个表并且由于某种原因不能/不想重新创建它,请使用indexes:

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

【讨论】:

这在 android 10 上对我有用,因为在 android 上似乎完全忽略了在 create 语句中添加 UNIQUE(i, j)【参考方案4】:

请注意如何为您定义表,插入时会得到不同的结果。考虑以下



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> 

虽然插入/更新效果相同,但 id 会根据表定义类型而变化(请参阅第二个表,其中 'Alice' 现在有 id = 4;第一个表比我预期的要多要做到这一点,请保持 PRIMARY KEY 相同)。请注意这种影响。

【讨论】:

【参考方案5】:

为我工作

create table projects (
    _id integer primary key autoincrement,
    project_type text not null,
    name text not null,
    description text,
    last_updated datetime default current_timestamp,
    date_created datetime default current_timestamp,
    unique (project_type, name)
);

【讨论】:

以上是关于SQLite 表约束 - 在多个列上唯一的主要内容,如果未能解决你的问题,请参考以下文章

SQLite进阶-10.约束

在 MySQL Workbench EER 图中的多个列上创建唯一约束

数据库表的列约束

SQLite 约束

数据存储——SQLite数据库存储2

sqlte3 的约束