2011-03-16 87 views
5

我正在处理迁移功能。它从旧表读取数据并将其插入新数据。所有在后台工作的东西都是低优先级的。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) 

我总是在sqlite3_step (insert statement)上收到'约束失败'错误。为什么它发生了,我该如何解决这个问题?

UPD:据我所知,这是因为后台线程使用数据库句柄在主线程中打开。现在检查猜测。

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) 
+0

感谢您的更新。我编辑了我的答案,并添加了一些更有用(我希望)的信息。 – 2011-03-16 15:13:57

回答

7

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

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

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

INSERT INTO new_table 
SELECT column_list FROM old_table; 

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

select sql from sqlite_master where tbl_name = 'old_table_name'; 
select sql from sqlite_master where tbl_name = 'new_table_name'; 

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

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

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

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

select pk 
from old_table_name 
group by pk 
having count() > 1; 

你可能会考虑尝试手动迁移使用INSERT INTO . . . SELECT . . .数据如果失败,增加一个WHERE子句,直到您隔离错误的数据,以减少集的大小。

+1

没有。我没有使用foreign_keys。还有另一个线程可以成功执行插入。现在我甚至可以用相同的数据填充插入。情况没有变化。第二个线程总是无法插入数据。插入由互斥体保护,所以只有一个可能在一次。 – 2011-03-16 11:31:47

+0

添加了从SQLite中提取SQL DDL的指导。编辑您的原始问题,并插入这两个查询的结果。 – 2011-03-16 12:33:24

+0

在UPD我补充说,我试图执行插入相同的数据在2个线程多次。第一个线程(其中sqlite3 *被打开)工作总是好的,插入第二个没有工作。正如你可以从表模式中看到的一样 - pk在两个表中都是唯一的。 – 2011-03-16 15:40:03

1

只是为了防止任何人在此寻找“约束失败”错误消息,请确保您的Id列的类型为INTEGER,而不是INTEGER (0, 15)或其他东西。

背景

如果你的表中有一个名为Id,与INTEGER类型和设置主键列,SQLite的把它作为内置列RowId的别名。此列的工作方式与自动增量列相似。在我的情况下,这个列工作正常,直到某些表设计器(可能是由SQLite家伙为Visual Studio创建的)将列类型从INTEGER更改为INTEGER (0, 15),突然我的应用程序开始抛出Constraint failed异常。

相关问题