SQLiteテーブルから最後の自動インクリメントIDを取得するにはどうすればよいですか?


85

ID(主キー、自動インクリメント)列とコンテンツ(テキスト)列を持つメッセージテーブルがあります。
ユーザー名(主キー、テキスト)とハッシュの列を持つユーザーテーブルがあります。
メッセージは1人の送信者(ユーザー)から多くの受信者(ユーザー)に送信され、受信者(ユーザー)は多くのメッセージを持つことができます。
MessageID(MessagesテーブルのID列を参照)とRecipient(Usersテーブルのusername列を参照)の2つの列を持つMessages_Recipientsテーブルを作成しました。このテーブルは、受信者とメッセージの間の多対多の関係を表します。

だから、私が持っている質問はこれです。新しいメッセージのIDは、データベースに保存された後に作成されます。しかし、この新しいMessageIDを取得するために、追加したばかりのMessageRowへの参照を保持するにはどうすればよいですか?
もちろん、最後に追加された行をデータベースでいつでも検索できますが、マルチスレッド環境では別の行が返される可能性がありますか?

編集:私はSQLiteについて理解しているので、を使用できますSELECT last_insert_rowid()。しかし、ADO.Netからこのステートメントを呼び出すにはどうすればよいですか?

私の永続性コード(メッセージとmessagesRecipientsはDataTablesです):

public void Persist(Message message)
{
    pm_databaseDataSet.MessagesRow messagerow;
    messagerow=messages.AddMessagesRow(message.Sender,
                            message.TimeSent.ToFileTime(),
                            message.Content,
                            message.TimeCreated.ToFileTime());
    UpdateMessages();
    var x = messagerow;//I hoped the messagerow would hold a
    //reference to the new row in the Messages table, but it does not.
    foreach (var recipient in message.Recipients)
    {
        var row = messagesRecipients.NewMessages_RecipientsRow();
        row.Recipient = recipient;
        //row.MessageID= How do I find this??
        messagesRecipients.AddMessages_RecipientsRow(row);
        UpdateMessagesRecipients();//method not shown
    } 

}

private void UpdateMessages()
{
    messagesAdapter.Update(messages);
    messagesAdapter.Fill(messages);
}

私はSQlite(ADO.Netバージョン)を使用しています
Dabblernl 2010年

回答:


89

SQL Serverでは、SELECT SCOPE_IDENTITY()を使用して、現在のプロセスの最後のID値を取得します。

SQliteを使用すると、自動インクリメントのように見えます

SELECT last_insert_rowid()

挿入直後。

http://www.mail-archive.com/sqlite-users@sqlite.org/msg09429.html

この値を取得するためのコメントへの回答として、次のようなSQLまたはOleDbコードを使用する必要があります。

using (SqlConnection conn = new SqlConnection(connString))
{
    string sql = "SELECT last_insert_rowid()";
    SqlCommand cmd = new SqlCommand(sql, conn);
    conn.Open();
    int lastID = (Int32) cmd.ExecuteScalar();
}

2
ありがとうございました!残念ながら、DataTableの更新に使用される接続を閉じる前にlast_insert_rowid()関数を呼び出す必要があるため、機能しません。これは...かかわらのSQLiteの癖かもしれ
Dabblernl

1
申し訳ありませんが、はい、それはおそらく本当です。messagesAdapter.Update(messages);の後に実行してみましたか?
MikeW 2010年

2
@Dabblernlは別の回答の方が信頼性が高いようです。別の回答の方が役立つと思われる場合は、受け入れられた回答を変更することをお勧めします
MikeW 2014

ただし、RowIdは常にPRIMARYKEYと同じであるとは限りません。を除くIf the table has a column of type INTEGER PRIMARY KEY then that column is another alias for the rowid.
–КоеКто 2018

110

もう1つのオプションは、システムテーブルを確認することですsqlite_sequence。自動インクリメントの主キーを使用してテーブルを作成した場合、sqliteデータベースには自動的にそのテーブルがあります。このテーブルは、sqliteが自動インクリメントフィールドを追跡して、一部の行を削除した後、または一部の挿入が失敗した後でも主キーを繰り返さないようにするためのものです(詳細については、http://www.sqlite.org/autoincを参照してください)。 .html)。

したがって、このテーブルには、他の何かを挿入した後でも(もちろん、他のテーブルで!)、新しく挿入されたアイテムの主キーを見つけることができるという追加の利点があります。挿入が成功したことを確認した後(そうしないと、誤った番号が表示されます)、次のことを行うだけです。

select seq from sqlite_sequence where name="table_name"

1
シーケンスがインクリメントされたとき、および行が削除された後に機能します。
マレクバー

いい答えです。「SQLiteのDBブラウザ」で「sqlite_sequence」から行を削除すると、一部のテーブルの最後のIDが取得されなくなるのは不思議です。
CoolMind 2018

9

SELECT last_insert_rowid()マルチスレッド環境での使用に問題がありました。別のスレッドがautoincを持つ別のテーブルに挿入する場合、last_insert_rowidは新しいテーブルからautoinc値を返します。

これが彼らがドコでそれを述べているところです:

sqlite3_last_insert_rowid()関数の実行中に別のスレッドが同じデータベース接続で新しいINSERTを実行し、最後の挿入ROWIDを変更した場合、sqlite3_last_insert_rowid()によって返される値は予測できず、古いものと新しいもののどちらとも等しくない可能性があります。 rowidを挿入します。

それはsqlite.orgdocoからです


1
スレッドごとに個別の接続を使用できると思いますが、パフォーマンスに大きな影響があることに気づきました。私のシナリオでは、1秒あたり約15回の挿入しか実行できません。
フィデル

私の推測では、別々のスレッドは同じ問題になるでしょう。残念ながら、これまでのところスレッドセーフな回避策はないようです。私の勘では、複数のトランザクションでは十分ではないので、注意してください:|
rogerdpack 2017年

5

@polyglotソリューションのサンプルコード

SQLiteCommand sql_cmd;
sql_cmd.CommandText = "select seq from sqlite_sequence where name='myTable'; ";
int newId = Convert.ToInt32( sql_cmd.ExecuteScalar( ) );

4

よると、最後の挿入行のIDを取得するAndroidのsqliteは別のクエリがあります:

SELECT rowid from your_table_name order by ROWID DESC limit 1

1
ROWIDを見つける前にソートアルゴリズムを実行するため、このオプションは、パフォーマンスの低下を持っている
シニアリブレ

2
おそらくそれは最適ではありませんが、接続が閉じられて再び開かれると実際に機能し、他の2つの解決策は私には適していませんでした。
Francine DeGroodTaylor19年

次のバリアントはを回避しORDER BYます。より高速でなければなりませんが、私はそれをテストしませんでした:SELECT MAX(rowid) FROM your_table_name
tanius
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.