使用带整数列的SQLite FTS3

使用带整数列的SQLite FTS3,sql,join,sqlite,fts3,Sql,Join,Sqlite,Fts3,我想使用SQLite FTS3 FTS4,实际上是用整型列索引一个表,概念上是这样的: CREATE VIRTUAL TABLE whole (document INTEGER, page INTEGER, content TEXT, UNIQUE(document, page)) USING fts4(); 我知道FTS3将rowid以外的所有列都视为文本,因此我必须使用两个表: CREATE VIRTUAL TABLE data USING fts4(); CREATE TABL

我想使用SQLite FTS3 FTS4,实际上是用整型列索引一个表,概念上是这样的:

CREATE VIRTUAL TABLE whole (document INTEGER, page INTEGER, content TEXT, 
    UNIQUE(document, page)) USING fts4();
我知道FTS3将rowid以外的所有列都视为文本,因此我必须使用两个表:

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';
我认为自然连接要求我确保rowid保持同步,但最好的方法是什么?我应该使用外键还是其他约束?子选择是否比联接更好

我想插入数据库中已有的文档和页面,以覆盖文本内容。这是通过SQL编程实现的,还是我必须检查info表中是否已经存在该行

我还想从给定文档的两个表中删除—有没有一种方法可以在一条语句中实现这一点

所有的建议都收到了,非常感谢,但由于我是一名SQL新手,代码示例尤其值得赞赏

更新:我根本不清楚如何在这里创建外键约束。如果我选择元数据作为我的首选父表,在没有双向约束的情况下:

PRAGMA foreign_keys = ON;
CREATE TABLE metadata (document INTEGER, page INTEGER);
CREATE VIRTUAL TABLE data USING fts4(content TEXT, docid REFERENCES metadata);
我得到错误:vtable构造函数失败:数据毫不奇怪,因为docid是rowid的别名,但当然我不能使用其他列,因为除rowid之外的所有列都必须是文本

然而,如果我尝试另一种方式:

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);

我得到一个错误:外键不匹配。

我想大多数DBA都会同意,如果您使用SQL,您应该利用它提供的所有功能

外键是我推荐的一般路线,并且有文档记录

一般来说,对于SQL数据库,您永远不应该手动强制执行一致性。特别是在这样的情况下,适合使用外键

对于DELETE-FROM的情况,SQLite不支持cascade关键字,比如说MS-SQL,但是它有触发器,允许您进行这种行为。可以找到SQLite触发器的文档


最后,我将跳过自然连接。

简而言之,在涉及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 create triggers在元数据和数据表的直接操作上引发异常,但这可能是过分的。同样,我不需要整个表的更新触发器。

显然,SQLite现在支持级联删除,但这并没有多大用处,因为我无法使外键约束起作用,请参见上面的更新。请确认:当您说跳过自然连接时,您的意思是使用子选择吗?FTS表不支持除docid/Rowid之外的任何外键或索引您是否使用外键创建了虚拟表?@Maragues否,并且您也不能真正实施相同的约束-请参阅下面我的答案。AFAICT虚拟表实际上只是带有SQL接口的程序。