NodeJS SQLite外键(在删除级联时)和SQLITE_CONSTRAINT

ugmeyewa  于 2023-08-04  发布在  Node.js
关注(0)|答案(2)|浏览(95)

概述:我有一个父/子表关系,其中子表可能包含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
);

字符串
在启动时,在连接到DB后,我确保启用FK:

PRAGMA foreign_keys = ON;


其他详情:

  • SQLite版本:3.7.17
  • 访问:node-sqlite3
  • 精确误差:Error: SQLITE_CONSTRAINT: FOREIGN KEY constraint failed

这是因为我后来添加了约束吗?(请参阅更新1)如何在不丢失数据的情况下修复此问题?

更新1

我可以确认只有选择消息(我相信,添加到message_Meta的message beforeON DELETE CASCADE中的消息)会导致约束错误。其他人删除刚刚好,并正确地取出相关的message_Meta记录。

vcirk6k6

vcirk6k61#

回答我自己的问题--经过几个小时的尝试,我找到了问题:

  • 当我最初添加ON DELETE CASCADE子句时,我将原始的message_meta表重命名为message_meta_backup,创建一个带有该子句的新表,然后将数据移动到其中:SELECT * FROM message_meta_backup INSERT INTO message_meta;。我 * 没有 * 做的是删除备份表。
  • 由于#1或相关的东西,我的数据库内部的东西被损坏或混淆。
    我尝试了什么(不起作用):
  • REINDEX;
  • 只需删除备份表:DROP TABLE message_meta_backup;
  • ……还有一些我忘记的事情:)
    什么工作:

最后,使用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>


(no错误提示)

vx6bjr1n

vx6bjr1n2#

我只会补充说,我有这个问题时,试图删除通过Db浏览器的SQLite图形用户界面。当我从sqlite shell运行该命令时,它没有任何问题。DB浏览器必须添加一些不必要的步骤。

相关问题