我使用CREATE TABLE AS
语法在Sqlite 中创建了一个基于SELECT
语句创建表的表.现在这个表没有主键,但我想添加一个.
执行ALTER TABLE table_name ADD PRIMARY KEY(col1, col2,...)
给出语法错误"near PRIMARY"
有没有办法在表创建期间或之后在Sqlite中添加主键?
编辑:"在创作过程中"我的意思是在创作过程中CREATE TABLE AS
.
创建后,您无法以任何重要方式修改SQLite表.接受的建议解决方案是创建一个具有正确要求的新表并将数据复制到其中,然后删除旧表.
这是关于此的官方文档:http://sqlite.org/faq.html#q11
只要您使用CREATE TABLE
,如果您在单个字段上创建主键,则可以使用:
CREATE TABLE mytable ( field1 TEXT, field2 INTEGER PRIMARY KEY, field3 BLOB, );
使用CREATE TABLE
,您还可以始终使用以下方法在一个或多个字段上创建主键:
CREATE TABLE mytable ( field1 TEXT, field2 INTEGER, field3 BLOB, PRIMARY KEY (field2, field1) );
参考:http://www.sqlite.org/lang_createtable.html
这个答案没有解决表格的变化.
我之后尝试通过直接更改sqlite_master表来添加主键.这个技巧似乎有效.当然这是一个黑客的解决方案.
简而言之:在表上创建一个常规(唯一)索引,然后使模式可写并将索引的名称更改为sqlite保留的形式以标识主键索引(即sqlite_autoindex_XXX_1,其中XXX是表名)并将sql字符串设置为NULL.最后更改表定义本身.一个pittfal:在重新打开数据库之前,sqlite看不到索引名称的更改.这似乎是一个错误,但不是一个严重的错误(即使没有重新打开数据库,你仍然可以使用它).
假设表格如下:
CREATE TABLE tab1(i INTEGER, j INTEGER, t TEXT);
然后我做了以下事情:
BEGIN; CREATE INDEX pk_tab1 ON tab1(i,j); pragma writable_schema=1; UPDATE sqlite_master SET name='sqlite_autoindex_tab1_1',sql=null WHERE name='pk_tab1'; UPDATE sqlite_master SET sql='CREATE TABLE tab1(i integer,j integer,t text,primary key(i,j))' WHERE name='tab1'; COMMIT;
一些测试(在sqlite shell中):
sqlite> explain query plan select * from tab1 order by i,j; 0|0|0|SCAN TABLE tab1 USING INDEX sqlite_autoindex_tab1_1 sqlite> drop index sqlite_autoindex_tab1_1; Error: index associated with UNIQUE or PRIMARY KEY constraint cannot be dropped
根据有关表创建的sqlite 文档,使用create table作为select会生成一个没有约束且没有主键的新表.
但是,文档还说主键和唯一索引在逻辑上是等效的(请参阅约束部分):
在大多数情况下,UNIQUE和PRIMARY KEY约束是通过在数据库中创建唯一索引来实现的.(例外是关于WITHOUT ROWID表的INTEGER PRIMARY KEY和PRIMARY KEY.)因此,以下模式在逻辑上是等价的:
CREATE TABLE t1(a, b UNIQUE); CREATE TABLE t1(a, b PRIMARY KEY); CREATE TABLE t1(a, b); CREATE UNIQUE INDEX t1b ON t1(b);
因此,即使您无法通过SQL alter语法更改表定义,也可以通过使用唯一索引获得相同的主键效果.
此外,任何表(除了那些没有rowid语法创建的表)都有一个内部整数列,称为"rowid".根据文档,您可以使用此内部列来检索/修改记录表.
你可以这样做:
CREATE TABLE mytable ( field1 text, field2 text, field3 integer, PRIMARY KEY (field1, field2) );