同时选择和插入时sqlite和'约束失败'错误

Evg*_*nov 6 sql sqlite

我正在研究迁移功能.它从旧表中读取数据并将其插入新表中.所有那些在低优先级的后台线程中工作的东西.

我在伪代码中的步骤.

sqlite3_prepare_stmt (select statement)
sqlite3_prepare_stmt (insert statement)

while (sqlite3_step (select statement) == SQLITE_ROW)
{
    get data from select row results
    sqlite3_bind select results to insert statement
    sqlite3_step (insert statement)
    sqlite3_reset (insert statement)
}

sqlite3_reset (select statement)
Run Code Online (Sandbox Code Playgroud)

我总是得到'约束失败'的错误sqlite3_step (insert statement).为什么会发生这种情况以及如何解决这个问题?

UPD:因为我知道发生了,因为后台线程使用在主线程中打开的db句柄.现在检查猜测.

UPD2:

sqlite> select sql from sqlite_master where tbl_name = 'tiles';
CREATE TABLE tiles('pk' INTEGER PRIMARY KEY, 'data' BLOB, 'x' INTEGER, 'y' INTEGER, 'z' INTEGER, 'importKey' INTEGER)
sqlite> select sql from sqlite_master where tbl_name = 'tiles_v2';
CREATE TABLE tiles_v2 (pk int primary key, x int, y int, z int, layer int, data blob, timestamp real)
Run Code Online (Sandbox Code Playgroud)

Mik*_*ll' 9

这可能意味着您的insert语句违反了新表中的约束.可以是主键约束,唯一约束,外键约束(如果您正在使用PRAGMA foreign_keys = ON;),等等.

您可以通过删除约束,更正数据或删除数据来解决此问题.删除约束通常是一件坏事,但这取决于应用程序.

是否有令人信服的理由一次一行地复制数据而不是一组?

INSERT INTO new_table
SELECT column_list FROM old_table;
Run Code Online (Sandbox Code Playgroud)

如果需要帮助来识别约束,请编辑原始问题,并发布这两个SQLite查询的输出.

select sql from sqlite_master where tbl_name = 'old_table_name';
select sql from sqlite_master where tbl_name = 'new_table_name';
Run Code Online (Sandbox Code Playgroud)

更新:根据这两个查询的输出,我只看到一个约束 - 每个表中的主键约束.如果尚未在这些表上构建任何触发器,则唯一可能失败的约束是主键约束.约束失败的唯一方法是,如果您尝试插入两行具有相同值的'pk'.

我想这可能会以几种不同的方式发生.

  • 旧表在"pk"列中有重复值.
  • 在将数据插入新表之前,执行迁移的代码会更改或注入重复值.
  • 另一个可能在不同计算机上运行的进程是在您不知情的情况下插入或更新数据.
  • 我还没有想到的其他原因.:-)

您可以通过运行此查询来确定旧表中是否存在重复的"pk"值.

select pk 
from old_table_name
group by pk
having count() > 1;
Run Code Online (Sandbox Code Playgroud)

您可能会考虑尝试手动迁移数据使用INSERT INTO . . . SELECT . . .如果失败,请添加WHERE子句以减小集合的大小,直到您隔离坏数据.