我正在研究迁移功能。它从旧表中读取数据并将其插入新表中。所有那些在后台线程中工作的东西都是低优先级的。
我在伪代码中的步骤。
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:因为我知道发生这种情况是因为后台线程使用在主线程中打开的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)
答案 0 :(得分:9)
这可能意味着您的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”值。
select pk
from old_table_name
group by pk
having count() > 1;
您可能会考虑尝试使用INSERT INTO . . . SELECT . . .
手动迁移数据如果失败,请添加WHERE子句以减小集的大小,直到您隔离坏数据为止。
答案 1 :(得分:2)
万一有人在这里寻找"约束失败"错误消息,请确保您的Id
列的类型为INTEGER
,而不是INTEGER (0, 15)
或其他类型。
<强>背景强>
如果您的表中有一个名为Id
的列,其类型为INTEGER
并设置为主键,则SQLite会将其视为内置列RowId
的别名。此列的作用类似于自动增量列。在我的情况下,这个专栏工作正常,直到一些表设计器(可能是SQLite人为Visual Studio创建的那个)将列类型从INTEGER
更改为INTEGER (0, 15)
并且突然我的应用程序开始抛出{ {1}}例外。
答案 2 :(得分:1)
只是为了让它更清晰:
确保您使用的数据类型正确,我使用int
代替integer
来创建这样的tmy表:
id int primary key not null
我长时间在约束问题上卡住 ...... 只需确保在创建数据库时正确输入数据类型。
答案 3 :(得分:0)
发生此错误的原因之一是也为唯一行插入重复数据。检查所有唯一和密钥是否有重复数据。
答案 4 :(得分:0)
我发现用sqlite排除外键约束错误很麻烦,尤其是在大型数据集上。但是,以下方法可帮助您确定有问题的关系。
PRAGMA foreign_keys = 0;
PRAGMA foreign_keys = 1;
PRAGMA foreign_key_check(table-name);
就我而言,它显示了13行带有无效引用。
答案 5 :(得分:0)
今天我遇到了类似的错误:CHECK constraint failed: profile
首先我读了 here 什么是约束。
<块引用>CONSTRAINTS 是一个完整性,它定义了一些条件 插入或插入时限制列包含真实数据 更新或删除。我们可以使用两种类型的约束,即 列级或表级约束。列级约束 只能应用于表级别的特定列 约束可以应用于整个表。
然后发现我需要检查数据库是如何创建的,因为我使用了 sqlalchemy 和 sqlite3 方言,我不得不检查表 schema
。 Schema 将显示实际的数据库结构。
sqlite3 >>> .schema
CREATE TABLE profile (
id INTEGER NOT NULL,
...
forum_copy_exist BOOLEAN DEFAULT 'false',
forum_deleted BOOLEAN DEFAULT 'true',
PRIMARY KEY (id),
UNIQUE (id),
UNIQUE (login_name),
UNIQUE (forum_name),
CHECK (email_verified IN (0, 1)),
UNIQUE (uid),
CHECK (forum_copy_exist IN (0, 1)),
CHECK (forum_deleted IN (0, 1))
所以在这里我发现布尔值 CHECK 总是 0 或 1 并且我使用列默认值作为“false”,所以每次我没有 forum_copy_exist 或 forum_deleted 值时,插入了 false,因为 false 是无效值,它会抛出错误, 并且没有插入行。
因此更改数据库默认为:
forum_copy_exist BOOLEAN DEFAULT '0',
forum_deleted BOOLEAN DEFAULT '0',
解决了这个问题。
在 postgresql 中,我认为 false 是有效值。所以这取决于数据库架构是如何创建的。
希望这会在未来对其他人有所帮助。