Sqlite3 : Creating a new table from an old table is not populating the sqlite_sequence table correctly

标签 sqlite

我正在尝试根据 this answer 删除表上的非空约束.但是,它似乎没有在 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

我已经这样做了大约三遍,但我无法让它工作。我最终做了一个
INSERT INTO sqlite_sequence VALUES ('post', 114);

一切似乎都运行良好

但当然,文档有这样的说法:

The content of the sqlite_sequence table can be modified using ordinary UPDATE, INSERT, and DELETE statements. But making modifications to this table will likely perturb the AUTOINCREMENT key generation algorithm. Make sure you know what you are doing before you undertake such changes.



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

最佳答案

对于表格的声明:

INSERT INTO this SELECT * FROM that;

SQLite 有一个特殊的传输优化,可以复制整行,而无需对行值进行解码和编码。
  • 当表结构简单(如 foo )时,总是可以使用这种优化。
  • 某些功能(例如外键约束)与此优化不兼容。
  • 并且在某些情况下,例如当存在 UNIQUE 约束时,这种优化只有在目标表为空时才能起作用。

  • 在第三种情况下,为语句生成的代码检查表是否为空。如果为空,则传输优化完成,程序停止;如果它不为空,则跳转到正常进行读/写的第二部分。但是,执行空表检查的代码 forgot to update the sqlite_sequence table在停止程序之前。

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

    This bug在版本 3.6.16 中引入,was fixed in version 3.15.0 .

    关于Sqlite3 : Creating a new table from an old table is not populating the sqlite_sequence table correctly,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39820552/

    相关文章:

    android - 在 Android 中处理大型数据库

    r - 如何将列重写(复制)到现有的SQLite数据库中

    android - 连接 ROOM 数据库中的表

    安卓应用 : Old database still exists after switching to room database

    ruby-on-rails - 尝试显示时间时出现NoMethodError

    ruby-on-rails - Rails 3.1 应用程序无法安装 sqlite3 gem,因为库已过时

    mysql - 使用 Django 从数据库中选择用于聚合计算的日期格式

    sqlite - 如何比较 SQLite 中的两个日期?

    php - 违反完整性约束 : 19 NOT NULL constraint failed for something not in migration table

    java - 如何从 sqlite 中检索列并将其存储到数组中?