Predict next auto-inserted row id (SQLite)

前端 未结 11 1320
予麋鹿
予麋鹿 2020-12-03 17:23

I\'m trying to find if there is a reliable way (using SQLite) to find the ID of the next row to be inserted, before it gets inserted. I need to use the id for anoth

相关标签:
11条回答
  • 2020-12-03 17:42

    Either scrapping or committing a series of database operations all at once is exactly what transactions are for. Query BEGIN; before the user starts fiddling and COMMIT; once he/she's done. You're guaranteed that either all the changes are applied (if you commit) or everything is scrapped (if you query ROLLBACK;, if the program crashes, power goes out, etc). Once you read from the db, you're also guaranteed that the data is good until the end of the transaction, so you can grab MAX(id) or whatever you want without worrying about race conditions.

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

    0 讨论(0)
  • 2020-12-03 17:45
    select max(id) from particular_table;
    

    The next id will be +1 from the maximum id.

    0 讨论(0)
  • 2020-12-03 17:46

    I realize your application using SQLite is small and SQLite has its own semantics. Other solutions posted here may well have the effect that you want in this specific setting, but in my view every single one of them I have read so far is fundamentally incorrect and should be avoided.

    In a normal environment holding a transaction for user input should be avoided at all costs. The way to handle this, if you need to store intermediate data, is to write the information to a scratch table for this purpose and then attempt to write all of the information in an atomic transaction. Holding transactions invites deadlocks and concurrency nightmares in a multi-user environment.

    In most environments you cannot assume data retrieved via SELECT within a transaction is repeatable. For example

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

    Subsequent to UPDATE the value of balance may well be changed. Sometimes you can get around this by updating the row(s) your interested in Bank first within a transaction as this is guaranteed to lock the row preventing further updates from changing its value until your transaction has completed.

    However, sometimes a better way to ensure consistency in this case is to check your assumptions about the contents of the data in the WHERE clause of the update and check row count in the application. In the example above when you "UPDATE Bank" the WHERE clause should provide the expected current value of balance:

    WHERE Balance = valuefromselect
    

    If the expected balance no longer matches neither does the WHERE condition -- UPDATE does nothing and rowcount returns 0. This tells you there was a concurrency issue and you need to rerun the operation again when something else isn't trying to change your data at the same time.

    0 讨论(0)
  • 2020-12-03 17:55

    Insert the row with an INVALID flag of some kind, Get the ID, edit it, as needed, delete if necessary or mark as valid. That and don't worry about gaps in the sequence

    BTW, you will need to figure out how to do the invalid part yourself. Marking something as NULL might work depending on the specifics.

    Edit: If you can, use Eevee's suggestion of using proper transactions. It's a lot less work.

    0 讨论(0)
  • 2020-12-03 17:55
    select max(id) from particular_table is unreliable for the reason below..
    

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

    "The normal ROWID selection algorithm described above will generate monotonically increasing unique ROWIDs as long as you never use the maximum ROWID value and you never delete the entry in the table with the largest ROWID. If you ever delete rows or if you ever create a row with the maximum possible ROWID, then ROWIDs from previously deleted rows might be reused when creating new rows and newly created ROWIDs might not be in strictly ascending order."

    0 讨论(0)
  • 2020-12-03 17:56

    You can probably get away with adding 1 to the value returned by sqlite3_last_insert_rowid under certain conditions, for example, using the same database connection and there are no other concurrent writers. Of course, you may refer to the sqlite source code to back up these assumptions.

    However, you might also seriously consider using a different approach that doesn't require predicting the next ID. Even if you get it right for the version of sqlite you're using, things could change in the future and it will certainly make moving to a different database more difficult.

    0 讨论(0)
提交回复
热议问题