SQLite的外键,ON DELETE CASCADE和SQLITE_CONSTRAINT

问题描述:

概述: 我有一个父/子表关系,那里的孩子可能包含2:n条记录与FK的回父。 当试图从父项中删除时,我得到一个SQLITE_CONSTRAINT错误。这是意外的,因为我已启用FK,让孩子注册ON DELETE CASCADE,并有足够新的SQLite版本。SQLite的外键,ON DELETE CASCADE和SQLITE_CONSTRAINT

然而:我的孩子表原本没有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 
); 

在启动时,连接到数据库的I确保FK的启用后直接:

PRAGMA foreign_keys = ON; 

其他详情:

  • SQLite的版本: 3.7.17
  • 访问:node-sqlite3
  • 确切错误:Error: SQLITE_CONSTRAINT: FOREIGN KEY constraint failed

这是造成我后来添加的约束的事实? (请参阅更新1) 如何修复此问题而不丢失数据?

更新1
我可以确认,仅选择消息(我相信,作为加入到该message_meta均消息之前ON DELETE CASCADE消息)导致约束错误。其他人删除得很好,并正确地取出相关的message_meta记录。

+0

显示实际的错误信息。 –

+0

@CL:错误:SQLITE_CONSTRAINT:FOREIGN KEY约束失败(也更新了OP) – NuSkooler

+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;
  • ...等种种事情,我忘了:)

Wha牛逼没有工作:
终于结束了什么工作一度下探备份表,并使用sqlite3外壳的.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> 

(!没有错误给出)