我想使用SQLite FTS3(实际上是FTS4)来索引具有整数列的表,概念上是这样的:
CREATE VIRTUAL TABLE whole (document INTEGER, page INTEGER, content TEXT,
UNIQUE(document, page)) USING fts4();
我知道FTS3将rowid以外的所有列都视为TEXT,所以我必须使用两个表:
CREATE VIRTUAL TABLE data USING fts4();
CREATE TABLE metadata(document INTEGER, page INTEGER, UNIQUE(document, page));
我希望能够查询文档或给定文档中的页面:
SELECT DISTINCT document FROM metadata NATURAL JOIN data WHERE content MATCH 'foo';
SELECT page FROM metadata NATURAL JOIN data
WHERE document = 123 AND content MATCH 'foo';
我认为NATURAL JOIN要求我确保rowid保持同步,但最好的方法是什么?我应该使用FOREIGN KEY还是其他约束?子选择会比连接更好吗?
我想插入数据库中已有的文档和页面来覆盖文本内容。这可能通过SQL以编程方式进行,还是我必须检查信息表中是否已存在该行?
我也想要在给定文档的两个表中删除 - 有没有办法在单个语句中执行此操作?
感谢所有建议,但由于我是SQL新手,代码示例特别受欢迎!
更新:我不清楚如何在这里创建外键约束。如果我选择metadata
作为父表(在没有双向约束的情况下,这将是我的偏好):
PRAGMA foreign_keys = ON;
CREATE TABLE metadata (document INTEGER, page INTEGER);
CREATE VIRTUAL TABLE data USING fts4(content TEXT, docid REFERENCES metadata);
我得到Error: vtable constructor failed: data
(不出所料,因为docid
是rowid
的别名,但我当然不能使用其他列,因为除了rowid
之外的所有列都必须是TEXT
)。
然而,如果我尝试相反的方式:
PRAGMA foreign_keys = ON;
CREATE VIRTUAL TABLE data USING fts4();
CREATE TABLE metadata (document INTEGER, page INTEGER, docid REFERENCES data);
表构造成功,但如果我尝试:
INSERT INTO data (docid, content) VALUES (123, 'testing');
INSERT INTO metadata (docid, document, page) VALUES (123, 12, 23);
我得到Error: foreign key mismatch
。
答案 0 :(得分:7)
简而言之,在涉及FTS3的情况下执行一致性非常困难。
SQLite虚拟表不允许触发器,FTS3表忽略约束和亲和力。
迄今为止我能做的最好的事情如下:
CREATE TABLE metadata (document INTEGER, page INTEGER, UNIQUE(document, page));
CREATE VIRTUAL TABLE data USING fts4();
CREATE VIEW whole AS SELECT metadata.rowid AS rowid, document, page, content
FROM metadata JOIN data ON metadata.rowid = data.rowid;
CREATE TRIGGER whole_insert INSTEAD OF INSERT ON whole
BEGIN
INSERT INTO metadata (document, page) VALUES (NEW.document, NEW.page);
INSERT INTO data (rowid, content) VALUES (last_insert_rowid(), NEW.content);
END;
CREATE TRIGGER whole_delete INSTEAD OF DELETE ON whole
BEGIN
DELETE FROM metadata WHERE rowid = OLD.rowid;
DELETE FROM data WHERE rowid = OLD.rowid;
END;
为了强制执行一致性,我可以(使用PRAGMA recursive_triggers = NO
)创建触发器以在metadata
和data
表上引发直接操作的异常,但这对我的目的来说可能有点过分(同样,我不需要UPDATE
表的whole
触发器。
答案 1 :(得分:-1)