【问题标题】:How do I get "insert or update" behaviour without using CONFLICT_REPLACE?如何在不使用 CONFLICT_REPLACE 的情况下获得“插入或更新”行为?
【发布时间】:2012-11-09 01:11:11
【问题描述】:

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

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

来自SQLite FTS3 and FTS4 Extensions 页面:

数据类型和列约束与每列一起指定。 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。

【问题讨论】:

    标签: android android-sqlite


    【解决方案1】:

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

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

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

    【讨论】:

      【解决方案2】:

      我也有同样的问题。我发现当我们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");
      

      【讨论】:

        【解决方案3】:

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

        if (cursor.moveToFirst()) {
                // record exists
            } else {
                // record not found
        

        【讨论】:

          【解决方案4】:

          我使用以下查询插入或替换

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

          而且它有效。但在这种情况下,您不能提供rowidrowid 将由数据库自己处理。

          【讨论】:

            猜你喜欢
            • 2011-11-02
            • 1970-01-01
            • 1970-01-01
            • 2016-07-14
            • 2016-04-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-07-10
            相关资源
            最近更新 更多