Bir SQLite tablosundan son otomatik artırılmış kimlik nasıl alınır?


85

Sütun kimliği (birincil anahtar, otomatik artış) ve İçerik (metin) içeren bir tablo Mesajlarım var.
Kullanıcı adı (birincil anahtar, metin) ve Hash sütunları olan bir tablom var.
Bir mesaj, bir Gönderen (kullanıcı) tarafından birçok alıcıya (kullanıcı) gönderilir ve bir alıcı (kullanıcı) birçok mesaj alabilir.
İki sütunlu bir Messages_Recipients tablosu oluşturdum: MessageID (Mesajlar tablosunun ID sütununa ve Alıcıya (Kullanıcılar tablosundaki kullanıcı adı sütununa atıfta bulunarak) Bu tablo, alıcılar ve mesajlar arasındaki çoktan çoğa ilişkiyi temsil eder.

Yani, sorduğum soru bu. Yeni mesajın kimliği, veri tabanında saklandıktan sonra oluşturulacaktır. Ancak bu yeni MessageID'yi almak için az önce eklediğim MessageRow'a bir referansı nasıl tutabilirim?
Tabi ki eklenen son satır için her zaman veritabanında arama yapabilirim, ancak bu, çok iş parçacıklı bir ortamda farklı bir satır döndürebilir mi?

DÜZENLEME: SQLite için anladığım kadarıyla SELECT last_insert_rowid(). Ama bu ifadeyi ADO.Net'ten nasıl çağırırım?

Kalıcılık kodum (mesajlar ve mesajlarAlıcılar Veri Tablolarıdır):

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 sürümü) kullanıyorum
Dabblernl

Yanıtlar:


89

SQL Server ile mevcut işlemin son kimlik değerini almak için SCOPE_IDENTITY () SEÇİNİZ.

SQlite ile, yapacağınız bir otomatik artış gibi görünüyor

SELECT last_insert_rowid()

ekinizden hemen sonra.

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

Bu değeri almak için yorumunuza yanıt olarak SQL veya OleDb kodunu aşağıdaki gibi kullanmak isteyeceksiniz:

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
Tekrar teşekkürler! Maalesef, DataTable'ı güncellemek için kullanılan bağlantı kapatılmadan önce last_insert_rowid () işlevinin çağrılması gerektiğinden çalışmaz. Yine de bu SQLite'ın bir
tuhaflığı

1
Üzgünüm, evet bu muhtemelen doğrudur. Bunu messagesAdapter.Update (mesajlar) 'dan sonra çalıştırmayı denediniz mi?
MikeW

2
@Dabblernl başka bir yanıt daha güvenilir görünüyor, başka bir yanıtın daha yararlı olduğunu düşünüyorsanız, kabul edilen yanıtı değiştirmek isteyebilirsiniz
MikeW

Ancak RowId, PRIMARY KEY ile her zaman aynı değildir. HariçIf the table has a column of type INTEGER PRIMARY KEY then that column is another alias for the rowid.
Кое Кто

110

Diğer bir seçenek de sistem tablosuna bakmaktır sqlite_sequence. Otomatik artış birincil anahtarı ile herhangi bir tablo oluşturduysanız, sqlite veritabanınız bu tabloya otomatik olarak sahip olacaktır. Bu tablo, bazı satırları sildikten veya bazı ekleme başarısız olduktan sonra bile birincil anahtarı tekrarlamaması için sqlite'ın otomatik artış alanını takip etmesi içindir (bununla ilgili daha fazla bilgiyi buradan okuyun http://www.sqlite.org/autoinc .html ).

Bu nedenle, bu tablo ile, yeni eklenen öğenizin birincil anahtarını başka bir şey ekledikten sonra bile bulabilmenizin ek bir faydası vardır (diğer tablolarda, tabii ki!). Ekinizin başarılı olduğundan emin olduktan sonra (aksi takdirde yanlış bir numara alırsınız), yapmanız gereken tek şey:

select seq from sqlite_sequence where name="table_name"

1
Sıra artırıldığında ve satır silindikten sonra çalışır.
Marek Bar

İyi cevap. "SQLite için DB Tarayıcısı" nda "sqlite_sequence" dan bir satırı kaldırırsanız, artık bazı tablolar için son kimliği alamayacağınız gariptir.
CoolMind

9

Çok SELECT last_insert_rowid()iş parçacıklı bir ortamda kullanımla ilgili sorunlar yaşadım . Autoinc'e sahip başka bir tabloya başka bir iş parçacığı eklenirse, last_insert_rowid yeni tablodan autoinc değerini döndürür.

Bunu doco'da ifade ettikleri yer:

Sqlite3_last_insert_rowid () işlevi çalışırken ayrı bir iş parçacığı aynı veritabanı bağlantısında yeni bir INSERT gerçekleştirirse ve böylece son ekleme satır kimliğini değiştirirse, bu durumda sqlite3_last_insert_rowid () tarafından döndürülen değer öngörülemezdir ve eski veya yeniye eşit olmayabilir rowid ekleyin.

Bu sqlite.org doco'dan


1
Sanırım her iş parçacığı için ayrı bir bağlantı kullanabilirsiniz, ancak bunun büyük bir performans vuruşuna sahip olduğunu fark ettim. Senaryomda saniyede sadece 15 ekleme yapabiliyorum.
Fidel

Tahminim, ayrı iş parçacıkları aynı sorun olacaktır. Maalesef bugüne kadar iş parçacığı için güvenli bir çalışma yok gibi görünüyor, benim önsezim birden fazla işlemin yeterli olmayacağı yönünde ... bu yüzden dikkatli olun: |
rogerdpack

5

@Polyglot çözümünden örnek kod

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

4

Android Sqlite'a göre son ekleme satır kimliğini al , başka bir sorgu var:

SELECT rowid from your_table_name order by ROWID DESC limit 1

1
Bu seçenek, rowid'i bulmadan önce bir sıralama algoritması yürüttüğü için bir performans cezasına sahiptir
Sr. Libre

2
Belki daha az optimaldir, ancak aslında bağlantı kapanıp yeniden açıldıktan sonra çalışır ve diğer iki çözüm benim için çalışmadı.
Francine DeGrood Taylor

Aşağıdaki varyant bundan kaçınır ORDER BY. Daha hızlı olmalı, ancak bunu test etmedim:SELECT MAX(rowid) FROM your_table_name
tanius
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.