質問

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

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

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

役に立ちましたか?

解決

一連のデータベース操作を一度にスクラップまたはコミットすることは、まさにトランザクションの目的です。クエリ BEGIN; ユーザーがいじり始める前に、 COMMIT; 彼/彼女が終わったら。すべての変更が適用される (コミットした場合) か、すべてが破棄される (クエリした場合) ことが保証されます。 ROLLBACK;, 、プログラムがクラッシュした場合、電源が落ちた場合など)。データベースから読み取ると、トランザクションが終了するまでデータが正常であることも保証されるため、データを取得することができます。 MAX(id) 競合状態を気にすることなく、好きなことを何でもできます。

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

他のヒント

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

も参照してください。 SQLite の自動インクリメントに関する記事, 、上記の情報はそこから来ました。

乾杯!

おそらく、によって返される値に 1 を加算することで回避できるでしょう。 sqlite3_last_insert_rowid 特定の条件下 (たとえば、同じデータベース接続を使用しており、他の同時書き込み者がいない場合)。もちろん、これらの仮定を裏付けるために sqlite ソース コードを参照することもできます。

ただし、次の ID を予測する必要のない別のアプローチの使用を真剣に検討することもできます。使用している sqlite のバージョンに正しく対応できたとしても、将来状況が変わる可能性があり、別のデータベースへの移行がより困難になることは確実です。

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

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

編集: 可能であれば、適切なトランザクションを使用するという Eevee の提案に従ってください。作業が大幅に減ります。

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 を返します。これは、同時実行性に問題があり、他の何かが同時にデータを変更しようとしていないときに操作を再実行する必要があることを示しています。

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 が厳密に昇順にならない可能性があります。

質問してから挿入するまでの間に何も挿入されないことを確認する方法がないため、これは不可能だと思います。(テーブルを挿入用にロックできるかもしれませんが、ダメです)

ところで、私は MySQL しか使用したことがありませんが、違いはないと思います)

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

last_insert_rowid() 値を選択します。

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

select max(id) from particular_table;

次のidは最大idから+1されます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top