1

我的 Android 应用程序使用 SQLite FTS3 表来提供全文搜索。我正在使用insertWithOnConflictwithCONFLICT_REPLACE更新我的数据库,如果需要插入新行或更新现有行(如果存在)。

我很惊讶地发现我的表最终包含重复的行——但看起来这是 SQLite 的 FTS 模块的文档化“功能”:

SQLite FTS3 和 FTS4 扩展页面:

数据类型和列约束与每列一起指定。FTS 和 SQLite 完全忽略了这些。

从命令行复制副本非常容易:

sqlite> CREATE VIRTUAL TABLE test_duplicates USING FTS3
   ...> (id INTEGER PRIMARY KEY, name TEXT);
sqlite> INSERT INTO test_duplicates (id, name) VALUES (1, "George");
sqlite> INSERT INTO test_duplicates (id, name) VALUES (1, "George");
sqlite> INSERT OR REPLACE INTO test_duplicates (id, name) VALUES (1, "George");
sqlite> SELECT * FROM test_duplicates;
1|George
1|George
1|George
sqlite>

我的问题是:复制 的行为的最佳(最简单、最强大)的方法是CONFLICT_REPLACE什么?

我目前的想法是(A)执行 SELECT,然后根据结果执行 UPDATE 或 INSERT,或者(B)盲目尝试删除现有行(可能存在也可能不存在)然后 INSERT。

4

4 回答 4

3

参考fts 文件,我找到了这一段:

...每个 FTS 表都有一个“rowid”列。FTS 表的 rowid 与普通 SQLite 表的 rowid 列的行为方式相同,只是在使用 VACUUM 命令重建数据库时,FTS 表的 rowid 列中存储的值保持不变。对于 FTS 表,允许将“docid”与通常的“rowid”、“oid”和“ oid ”标识符一起作为别名。尝试使用表中已存在的 docid 值插入或更新行是错误的,就像使用普通 SQLite 表一样。

这意味着您可以使用内置docid列作为主键并让 fts 表对其应用它的约束。

于 2012-11-12T10:59:54.257 回答
1

我也有同样的问题。我发现当我们CREATE VIRTUAL TABLE test_duplicates USING FTS3将创建一个名为的列时rowid,它是该表的主键,因此我们只需要使用它就rowid可以id正常工作。

如果你改变: INSERT INTO test_duplicates (id, name) VALUES (1, "George");

到:

INSERT INTO test_duplicates (rowid, id, name) VALUES (1, 1, "George");
INSERT INTO test_duplicates (rowid, id, name) VALUES (2, 2, "George");
于 2016-04-28T08:19:33.023 回答
0

我不会因此而受到赞扬。但我找不到我从中得到的原始链接。你做一个查询,然后:

if (cursor.moveToFirst()) {
        // record exists
    } else {
        // record not found
于 2012-11-09T01:16:58.910 回答
0

我对 INSERT OR REPLACE 使用以下查询

INSERT OR REPLACE INTO test_duplicates (`rowid`, `name`) VALUES 
((SELECT `rowid` FROM test_duplicates WHERE `name` = "George" LIMIT 1), "George")

它有效。但在这种情况下,您无法提供rowid. rowid将由数据库本身处理。

于 2019-04-16T14:08:19.337 回答