20

我正在尝试查找是否有可靠的方法(使用SQLite )在插入之前找到要插入的下一行的 ID 。我需要将 id 用于另一个插入语句,但没有立即插入和获取下一行的选项。

预测下一个 id 是否像获取最后一个 id 并添加一个一样简单?那是保证吗?

编辑:多一点推理......我不能立即插入,因为插入可能最终被用户取消。用户将进行一些更改,将存储 SQL 语句,然后用户可以从那里保存(一次插入所有行)或取消(不更改任何内容)。在程序崩溃的情况下,所需的功能是没有任何改变。

4

11 回答 11

28

试试SELECT * FROM SQLITE_SEQUENCE WHERE name='TABLE';。这将包含一个名为seq该字段的字段,该字段是所选表的最大数字。将此值加 1 以获得下一个 ID。

另请参阅SQLite Autoincrement 文章,这是上述信息的来源。

干杯!

于 2011-03-14T17:10:27.640 回答
16

一次性取消或提交一系列数据库操作正是事务的用途。BEGIN;在用户开始摆弄之前和COMMIT;他/她完成后查询。您可以保证所有更改都已应用(如果您提交)或所有内容都已报废(如果您查询ROLLBACK;,如果程序崩溃,断电等)。从数据库中读取数据后,您还可以保证数据在事务结束之前是良好的,因此您可以抓取MAX(id)或获取任何您想要的内容,而不必担心竞争条件。

http://www.sqlite.org/lang_transaction.html

于 2008-09-20T04:32:51.757 回答
3

在某些条件下,您可能可以在sqlite3_last_insert_rowid返回的值上加 1 ,例如,使用相同的数据库连接并且没有其他并发写入者。当然,您可以参考 sqlite 源代码来支持这些假设。

但是,您也可以认真考虑使用不需要预测下一个 ID 的不同方法。即使您使用的 sqlite 版本正确,将来也可能会发生变化,并且肯定会使迁移到不同的数据库变得更加困难。

于 2008-09-20T04:03:16.867 回答
2

插入带有某种 INVALID 标志的行,获取 ID,根据需要对其进行编辑,如有必要,删除或标记为有效。那并且不用担心序列中的间隙

顺便说一句,你需要弄清楚如何自己做无效的部分。根据具体情况,将某些内容标记为 NULL 可能会起作用。

编辑:如果可以,请使用 Eevee 的使用正确交易的建议。工作量少了很多。

于 2008-09-20T04:04:29.173 回答
2

我意识到您使用 SQLite 的应用程序很小,而且 SQLite 有自己的语义。此处发布的其他解决方案很可能会在此特定设置中产生您想要的效果,但在我看来,到目前为止我读过的每一个解决方案基本上都是不正确的,应该避免。

在正常环境中,应不惜一切代价避免为用户输入进行交易。如果您需要存储中间数据,处理此问题的方法是为此目的将信息写入临时表,然后尝试将所有信息写入原子事务中。在多用户环境中,持有事务会导致死锁和并发噩梦。

在大多数环境中,您不能假设在事务中通过 SELECT 检索的数据是可重复的。例如

SELECT Balance FROM Bank ...
UPDATE Bank SET Balance = valuefromselect + 1.00 WHERE ...

在 UPDATE 之后,余额的值很可能会发生变化。有时您可以通过在事务中首先更新您对 Bank 感兴趣的行来解决此问题,因为这可以保证锁定该行,防止进一步更新更改其值,直到您的事务完成。

但是,有时在这种情况下确保一致性的更好方法是检查您对更新的 WHERE 子句中数据内容的假设并检查应用程序中的行数。在上面的示例中,当您“更新银行”时,WHERE 子句应提供余额的预期当前值:

WHERE Balance = valuefromselect

如果预期余额不再匹配 WHERE 条件 - UPDATE 不执行任何操作,并且 rowcount 返回 0。这告诉您存在并发问题,并且您需要再次重新运行操作,而其他东西没有尝试更改您的数据同时。

于 2009-01-03T21:02:33.827 回答
2
select max(id) from particular_table is unreliable for the reason below..

http://www.sqlite.org/autoinc.html

“只要您从不使用最大 ROWID 值并且您从不删除表中具有最大 ROWID 的条目,上述常规 ROWID 选择算法将生成单调递增的唯一 ROWID。如果您曾经删除行或曾经创建行使用最大可能的 ROWID,则在创建新行时可能会重用以前删除的行中的 ROWID,并且新创建的 ROWID 可能不会严格按升序排列。”

于 2011-11-23T00:22:41.283 回答
0

我认为这无法完成,因为无法确保在您询问和插入之间不会插入任何内容。(您可能可以将表格锁定为插入,但 Yuck)

顺便说一句,我只使用了 MySQL,但我认为这不会有任何区别)

于 2008-09-20T03:50:23.247 回答
0

您很可能应该能够 +1 最近的 id。我会查看有序表中现有 ID 的所有(回溯一段时间)。它们是否一致,每一行的 ID 是否比最后一个多一个?如果是这样,你可能会没事的。但是,我会在代码中留下注释来解释该假设。执行锁定将有助于确保您在执行此操作时不会获得额外的行。

于 2008-09-20T03:50:26.803 回答
0

选择 last_insert_rowid() 值。

于 2008-09-20T03:50:43.247 回答
0

本主题中需要说明的大部分内容都已经包含......但是,在执行此操作时要非常小心竞争条件。如果两个人都打开了您的应用程序/网页/任何内容,其中一个人添加了一行,另一个用户将尝试插入具有相同 ID 的行,您将遇到很多问题。

于 2008-09-20T04:55:11.487 回答
0
select max(id) from particular_table;

下一个 id 将是最大 id 的 +1。

于 2011-03-08T13:03:43.990 回答