概述:
我有一个父/子表关系,其中子可能包含2:n个记录,其中FK返回到父级。 尝试从父级删除时,出现SQLITE_CONSTRAINT错误。这是意料之外的,因为我启用了FK,让孩子注册了ON DELETE CASCADE
,以及一个足够新的SQLite版本。
但是:我的子表最初没有ON DELETE CASCADE
。在将数据添加到父/子后,我添加了(并启用了FK)。从那里,我改名原来的孩子&使用约束创建了一个新表,最后移动到新表。
表格布局如下:
CREATE TABLE IF NOT EXISTS message (
message_id INTEGER PRIMARY KEY,
area_tag VARCHAR NOT NULL,
message_uuid VARCHAR(36) NOT NULL,
reply_to_message_id INTEGER,
to_user_name VARCHAR NOT NULL,
from_user_name VARCHAR NOT NULL,
subject, /* FTS @ message_fts */
message, /* FTS @ message_fts */
modified_timestamp DATETIME NOT NULL,
view_count INTEGER NOT NULL DEFAULT 0,
UNIQUE(message_uuid)
);
CREATE INDEX IF NOT EXISTS message_by_area_tag_index
ON message (area_tag);
CREATE VIRTUAL TABLE IF NOT EXISTS message_fts USING fts4 (
content="message",
subject,
message
);
CREATE TRIGGER IF NOT EXISTS message_before_update BEFORE UPDATE ON message BEGIN
DELETE FROM message_fts WHERE docid=old.rowid;
END;
CREATE TRIGGER IF NOT EXISTS message_before_delete BEFORE DELETE ON message BEGIN
DELETE FROM message_fts WHERE docid=old.rowid;
END;
CREATE TRIGGER IF NOT EXISTS message_after_update AFTER UPDATE ON message BEGIN
INSERT INTO message_fts(docid, subject, message) VALUES(new.rowid, new.subject, new.message);
END;
CREATE TRIGGER IF NOT EXISTS message_after_insert AFTER INSERT ON message BEGIN
INSERT INTO message_fts(docid, subject, message) VALUES(new.rowid, new.subject, new.message);
END;
CREATE TABLE IF NOT EXISTS message_meta (
message_id INTEGER NOT NULL,
meta_category INTEGER NOT NULL,
meta_name VARCHAR NOT NULL,
meta_value VARCHAR NOT NULL,
UNIQUE(message_id, meta_category, meta_name, meta_value),
FOREIGN KEY(message_id) REFERENCES message(message_id) ON DELETE CASCADE
);
启动时,在连接到数据库之后,我确保启用了FK:
PRAGMA foreign_keys = ON;
其他细节:
Error: SQLITE_CONSTRAINT: FOREIGN KEY constraint failed
这是因为我后来添加了约束吗?(参见更新1)
如何在不丢失数据的情况下解决此问题?
更新1 :
我可以确认只有选择的消息(我相信,消息 ON DELETE CASCADE
之前的消息添加到message_meta中)会导致约束错误。其他人删除就好并正确取出相关的message_meta记录。
答案 0 :(得分:0)
回答我自己的问题 - 经过几个小时尝试各种各样的事情后,我找到了问题:
当我最初添加ON DELETE CASCADE
子句时,我是通过将原始message_meta
表重命名为message_meta_backup
,使用该子句创建新表,然后移动数据来实现的。进入它:SELECT * FROM message_meta_backup INSERT INTO message_meta;
。我没有做的是删除备份表。
由于#1或其他相关内容,我的数据库内部的内容已损坏或混淆。
我尝试了什么(不起作用):
REINDEX;
DROP TABLE message_meta_backup;
DID的工作原理:
最终结果是使用sqlite3
shell .drop
命令删除备份表并完全重建数据库的组合:
> sqlite3 db/message.sqlite3
SQLite version 3.7.17 2013-05-20 00:56:22
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> drop table message_meta_backup;
sqlite> .quit
> sqlite3 db/message.sqlite3 ".dump" >> message_dump.sql
rm db/message.sqlite3
> cat message_dump.sql | sqlite3 db/message.sqlite3
我现在能够DELETE FROM message ...
并将其正确地将删除级联到message_meta
而没有令人讨厌的错误:
sqlite> DELETE FROM message WHERE message_id IN(SELECT message_id FROM message WHERE area_tag='some_area' ORDER BY message_id desc limit -1 offset 200);
sqlite>
(没有给出错误!)