【问题标题】:Retrieve Last Record in SQLite Table (again)检索 SQLite 表中的最后一条记录(再次)
【发布时间】:2012-08-01 19:35:49
【问题描述】:

我先搜索了几次,还有一个问题。

不知不觉,我找到的最佳答案在this SO 答案中。总结:

SELECT * FROM TABLE WHERE ID = (SELECT MAX(ID) FROM TABLE);

我想知道的是下面的方法是否也能正常工作(因为我懒得改变它,我碰巧喜欢它)。

SELECT * FROM TABLE ORDER BY ID DESC LIMIT 1

根据我们拥有的SQLite Autoincrement 文档,

如果插入时没有指定 ROWID,或者指定的 ROWID 的值为 NULL,则会自动创建适当的 ROWID。 通常的算法是给新创建的行一个比插入前表中最大的 ROWID 大一的 ROWID。如果表最初为空,则使用 1 的 ROWID。 [强调]

还有,

只要您从不使用最大 ROWID 值并且从不删除表中具有最大 ROWID 的条目,上述正常 ROWID 选择算法将生成单调递增的唯一 ROWID。 如果您曾经删除过行,或者曾经创建过具有最大可能 ROWID 的行,那么在创建新行时可能会重复使用先前删除的行中的 ROWID,并且新创建的 ROWID 可能不会严格按照升序排列。 [强调]

关于我提出的 SQL 语句的问题来自最后一句话。这似乎表明,如果您删除任何行,则可以重用先前删除的 ROWID,而不管是否使用了最大 ROWID。如果我们假设从未使用过最大 ROWID(手动或仅通过那么多记录),那么我们只需要担心删除记录。在这种情况下,第一个 SQLite 文档摘录听起来好像您不会在我的查询中遇到任何问题。

有人确定吗?

我喜欢我的查询,因为它只涉及一个选择(虽然,以订购为代价)。我想,我可能过于关注微小的优化,不是吗?

编辑: 实际上,重新查看上面引用的 SQLite 页面,我认为使用 AUTOINCREMENT 关键字可以保证 ROWID 单调递增。最后一节详细讨论了它。

如果列的类型为 INTEGER PRIMARY KEY AUTOINCREMENT,则使用稍微不同的 ROWID 选择算法。为新行选择的 ROWID 至少比以前存在于同一个表中的最大 ROWID 大一个。如果表以前从未包含任何数据,则使用 1 的 ROWID。如果该表之前保存了具有最大可能 ROWID 的行,则不允许新的 INSERT,并且任何插入新行的尝试都将失败并返回 SQLITE_FULL 错误。

现在对我来说似乎很清楚。只是无法填满表格(最多 9223372036854775807)。

对不起,我之前只略过这部分!

【问题讨论】:

  • 我没有发现问题。你的逻辑对我来说是合理的。重用 ROWID 背后的想法似乎是优化表空间和偏移量。
  • 如果您想保证选择最后一行的方法,请使用时间戳而不是 ROWID。 (假设您没有及时旅行或将系统时钟设置为过去)
  • @Sam 可能会比我的方法更好,因为使用自动递增 rowid 字段会使插入速度变慢。不过,对于大多数应用程序,我敢打赌这无关紧要。

标签: android sql sqlite


【解决方案1】:

我想我会在这里记录一下这两个查询的运行速度。
在一张有大约 15,000 行的表上,抓取其中的 1400 行,然后获取最后输入的行,这是我得到的结果:

SELECT macAddr, time, onPeakTotalIn, onPeakTotalOut, offPeakTotalIn, offPeakTotalOut FROM trafficMon WHERE macAddr="02:d2:ee:aa:aa:aa" ORDER BY time DESC LIMIT 1;

CPU 时间:用户 0.008124 sys 0.000000
虚拟机步骤:58741
全扫描步骤:14156

SELECT macAddr, time, onPeakTotalIn, onPeakTotalOut, offPeakTotalIn, offPeakTotalOut FROM trafficMon WHERE id = (SELECT MAX(id) FROM trafficMon WHERE macAddr="02:d2:ee:aa:aa:aa");

CPU 时间:用户 0.000295 系统 0.000000
虚拟机步骤:49
全扫描步骤:3

如您所见,明智地处理 MAX(id) 资源要容易得多,而且花费的时间要少得多。

虽然 0.008124s 一直都是个问题,但当您在基于 MIPS 的嵌入式设备(在我的例子中是路由器)上运行相同的命令时,在脚本中运行 20-30 倍以及一堆其他东西,这一切加起来。

希望有所帮助:)

鸭子

【讨论】:

    【解决方案2】:

    您显示的两个查询是等效的。

    至于它们是否返回最后一条记录,这取决于您所说的“最后”是什么意思。如果删除行,则不能依赖任一查询来返回最后插入的行。

    【讨论】:

    • 请查看我对问题的编辑。我认为通过正确声明的字段,他们可以确保返回插入的最后一行。即使存在已删除的行,除非我误解了最后的报价。
    • 是的,如果您使用AUTOINCREMENT,您将获得最后插入的行。
    • 谢谢!只是想在我实施之前确定一下。
    【解决方案3】:

    首先,您应该检索最后插入的行 id,然后从该行 id 中,您可以通过选择查询获取最后插入的记录。

    RowID = sqlite3_last_insert_rowid(sqlite3Database)
    
    SELECT * FROM tableName where RowID=RowID
    

    此选择语句将为您提供最后插入的记录

    this link.了解更多详情

    【讨论】:

    • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能会失效。
    • 是的,你是对的@MZaragoza 现在我已尝试澄清我的答案,感谢您的建议。
    【解决方案4】:

    如果表有一个类型为'autoincrement'的字段,那么最好使用:

    SELECT seq FROM sqlite_sequence WHERE name='TABLE_NAME'
    

    查看示例(表“客户”):

    SELECT seq FROM sqlite_sequence WHERE name='customers'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-21
      相关资源
      最近更新 更多