20

挿入される前に、挿入される次の行のIDを見つけるための信頼できる方法( SQLiteを使用)があるかどうかを見つけようとしています。別の挿入ステートメントにIDを使用する必要がありますが、次の行を即座に挿入して取得するオプションがありません。

次のIDの予測は、最後のIDを取得して追加するのと同じくらい簡単ですか?それは保証ですか?

編集:もう少し理由...挿入がユーザーによってキャンセルされる可能性があるため、すぐに挿入できません。ユーザーはいくつかの変更を行い、SQLステートメントが保存され、そこからユーザーは保存(すべての行を一度に挿入)またはキャンセル(何も変更しない)することができます。プログラムがクラッシュした場合、必要な機能は何も変更されないことです。

4

11 に答える 11

28

試してみてくださいSELECT * FROM SQLITE_SEQUENCE WHERE name='TABLE';seqこれには、選択したテーブルの最大数であるというフィールドが含まれます。次の ID を取得するには、この値に 1 を加算します。

上記の情報の出所である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

SQLiteを使用するアプリケーションは小さく、SQLiteには独自のセマンティクスがあることを理解しています。ここに掲載されている他の解決策は、この特定の設定で必要な効果をもたらす可能性がありますが、私の見解では、これまで読んだすべての解決策は根本的に正しくないため、避ける必要があります。

通常の環境では、ユーザー入力のトランザクションを保持することは絶対に避けてください。中間データを格納する必要がある場合、これを処理する方法は、この目的のために情報をスクラッチテーブルに書き込んでから、アトミックトランザクションですべての情報を書き込もうとすることです。トランザクションを保持すると、マルチユーザー環境でデッドロックと同時実行の悪夢が発生します。

ほとんどの環境では、トランザクション内でSELECTを介して取得されたデータが繰り返し可能であると想定することはできません。例えば

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

UPDATEに続いて、残高の値が変更される可能性があります。トランザクション内で最初に銀行に関心のある行を更新することでこれを回避できる場合があります。これにより、行がロックされ、トランザクションが完了するまで更新によって値が変更されないことが保証されます。

ただし、この場合の一貫性を確保するためのより良い方法は、更新のWHERE句のデータの内容に関する仮定を確認し、アプリケーションの行数を確認することです。上記の例では、「UPDATE Bank」の場合、WHERE句は残高の予想される現在の値を提供する必要があります。

WHERE Balance = valuefromselect

期待されるバランスが一致しなくなった場合、WHERE条件も一致しません。UPDATEは何も行わず、rowcountは0を返します。これは、同時実行の問題があったことを示しており、他の何かがデータを変更しようとしていないときに、操作を再実行する必要があります。同時に。

于 2009-01-03T21:02:33.827 に答える
2

ある種の INVALID フラグを持つ行を挿入し、ID を取得し、必要に応じて編集し、必要に応じて削除するか、有効としてマークします。それと、シーケンスのギャップについて心配する必要はありません

ところで、無効な部分を自分で行う方法を理解する必要があります。詳細によっては、何かを NULL としてマークしても機能する場合があります。

編集:可能であれば、適切なトランザクションを使用するという Eevee の提案を使用してください。それははるかに少ない仕事です。

于 2008-09-20T04:04:29.173 に答える
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

ほとんどの場合、最新のIDを+1できるはずです。順序付けされたテーブルにある既存のIDをすべて(しばらく前に)調べます。それらは一貫しており、各行のIDは最後のIDより1つ多いですか?もしそうなら、あなたはおそらく大丈夫でしょう。ただし、仮定を説明するコメントをコードに残しておきます。ロックを実行すると、これを実行している間も追加の行が取得されないことが保証されます。

于 2008-09-20T03:50:26.803 に答える
0

last_insert_rowid()値を選択します。

于 2008-09-20T03:50:43.247 に答える
0
select max(id) from particular_table;

次のIDは、最大IDから+1になります。

于 2011-03-08T13:03:43.990 に答える
0

このトピックで説明する必要があることのほとんどは、既に...ただし、これを行うときは競合状態に十分注意してください。2 人のユーザーが両方ともアプリケーション/Web ページ/その他を開いて、そのうちの 1 人が行を追加すると、他のユーザーが同じ ID で行を挿入しようとするため、多くの問題が発生します。

于 2008-09-20T04:55:11.487 に答える