Sqlite3:从旧表创建一个新表并没有正确填充sqlite_sequence表

时间:2016-10-02 19:02:20

标签: sqlite

我试图根据this answer在表上删除非空约束。但是,在执行此操作之后,它似乎不会在index中创建条目,即使我可以在使用测试表时使其正常工作。 有趣的是,如果我备份我的表,重新创建它,在其中插入两个假行,然后重复上述过程,正确填充sqlite_sequence表。但是,当我使用原始数据集时,该过程无法正常工作。

例如,这在测试表上可以正常工作:

sqlite_sequence

但是,当我在真实表上执行完全相同的命令时,它无法在CREATE TABLE foo ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, bar VARCHAR NOT NULL ); INSERT INTO foo (bar) VALUES ('foo'); INSERT INTO foo (bar) VALUES ('bar'); -- As expected, this shows foo | 2 SELECT * FROM sqlite_sequence WHERE name = 'foo'; BEGIN TRANSACTION; ALTER TABLE foo RENAME TO temp_foo; CREATE TABLE foo ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, bar VARCHAR ); INSERT INTO foo SELECT * from temp_foo; -- As expected, this shows foo | 2 SELECT * FROM sqlite_sequence WHERE name = 'foo'; COMMIT; 中添加条目。

sqlite_sequence

我已经做了大约三次,我无法让它发挥作用。我最终做了一个

sqlite> .schema post;
CREATE TABLE post (
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    user_id INTEGER NOT NULL,
    title VARCHAR NOT NULL,
    url_name VARCHAR NOT NULL,
    description VARCHAR NOT NULL,
    category_id INTEGER NOT NULL,
    content VARCHAR,
    is_published BOOLEAN,
    creation_date DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
    last_modified_date DATETIME DEFAULT CURRENT_TIMESTAMP,
    is_commenting_disabled BOOLEAN NOT NULL,
    CHECK (title <> ''),
    CHECK (url_name <> ''),
    CHECK (description <> ''),
    CHECK (content <> ''),
    FOREIGN KEY(user_id) REFERENCES user (id) ON DELETE CASCADE,
    UNIQUE (url_name),
    FOREIGN KEY(category_id) REFERENCES category (id) ON DELETE CASCADE,
    CHECK (is_published IN (0, 1)),
    CHECK (is_commenting_disabled IN (0, 1))
);
sqlite>
sqlite> select * from sqlite_sequence where name = 'post';
post|114
sqlite> 
sqlite> BEGIN TRANSACTION;
sqlite>
sqlite> ALTER TABLE post RENAME TO temp_post;
sqlite>
sqlite> CREATE TABLE post (
   ...>         id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
   ...>         user_id INTEGER NOT NULL,
   ...>         title VARCHAR NOT NULL,
   ...>         url_name VARCHAR NOT NULL,
   ...>         description VARCHAR,
   ...>         category_id INTEGER NOT NULL,
   ...>         content VARCHAR,
   ...>         is_published BOOLEAN,
   ...>         creation_date DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
   ...>         last_modified_date DATETIME DEFAULT CURRENT_TIMESTAMP,
   ...>         is_commenting_disabled BOOLEAN NOT NULL,
   ...>         CHECK (title <> ''),
   ...>         CHECK (url_name <> ''),
   ...>         CHECK (description <> ''),
   ...>         CHECK (content <> ''),
   ...>         FOREIGN KEY(user_id) REFERENCES user (id) ON DELETE CASCADE,
   ...>         UNIQUE (url_name),
   ...>         FOREIGN KEY(category_id) REFERENCES category (id) ON DELETE CASCADE,
   ...>         CHECK (is_published IN (0, 1)),
   ...>         CHECK (is_commenting_disabled IN (0, 1))
   ...> );
sqlite>
sqlite> INSERT INTO post SELECT * FROM temp_post;
sqlite>
sqlite> select * from sqlite_sequence WHERE name in ('temp_post', 'post');
temp_post|114
sqlite> COMMIT;
sqlite>
sqlite> select * from sqlite_sequence WHERE name in ('temp_post', 'post');
temp_post|114

一切似乎都运转良好

但当然,文档可以这样说:

  

可以使用普通的UPDATE,INSERT和DELETE语句修改sqlite_sequence表的内容。但是对此表进行修改可能会扰乱AUTOINCREMENT密钥生成算法。在进行此类更改之前,请确保您知道自己在做什么。

如前所述,如果我备份INSERT INTO sqlite_sequence VALUES ('post', 114); 表,然后重新创建它,然后在其中添加两个假行,然后重复上述过程,post表是正确的。我的原始数据集似乎有问题,但我不确定如何调试该问题。

1 个答案:

答案 0 :(得分:2)

表格声明:

INSERT INTO this SELECT * FROM that;

SQLite有一个特殊的传输优化,可以复制整行而无需对行值进行解码和编码。

  1. 当表格具有简单结构(例如foo)时,可以始终使用此优化。
  2. 某些功能(如外键约束)与此优化不兼容。
  3. 在某些情况下,例如当存在UNIQUE约束时,此优化仅在目标表为空时才有效。
  4. 在第三种情况下,为语句生成的代码检查表是否为空。如果为空,则完成传输优化,程序停止;如果它不为空,则跳转到正常进行读/写的第二部分。但是,在停止程序之前,执行空表的代码会检查forgot to update the sqlite_sequence table

    作为一种解决方法,通过启用外键检查将其移至第二种情况。

    This bug在版本3.6.16和was fixed in version 3.15.0中引入。