Làm cách nào để truy xuất ID tự động tăng cuối cùng từ bảng SQLite?


82

Tôi có một bảng Tin nhắn với các cột ID (khóa chính, tự động gia tăng) và Nội dung (văn bản).
Tôi có một bảng Người dùng với tên người dùng cột (khóa chính, văn bản) và Băm.
Một tin nhắn được gửi bởi một Người gửi (người dùng) đến nhiều người nhận (người dùng) và một người nhận (người dùng) có thể có nhiều tin nhắn.
Tôi đã tạo một bảng Messages_Recipthers với hai cột: MessageID (tham chiếu đến cột ID của bảng Tin nhắn và Người nhận (tham chiếu đến cột tên người dùng trong bảng Người dùng). Bảng này đại diện cho mối quan hệ nhiều đến nhiều giữa người nhận và thư.

Vì vậy, câu hỏi tôi có là này. ID của một tin nhắn mới sẽ được tạo sau khi nó đã được lưu trữ trong cơ sở dữ liệu. Nhưng làm cách nào tôi có thể giữ một tham chiếu đến MessageRow mà tôi vừa thêm để truy xuất MessageID mới này?
Tất nhiên, tôi luôn có thể tìm kiếm cơ sở dữ liệu cho hàng cuối cùng được thêm vào, nhưng điều đó có thể trả về một hàng khác trong môi trường đa luồng?

CHỈNH SỬA: Theo tôi hiểu về SQLite, bạn có thể sử dụng SELECT last_insert_rowid(). Nhưng làm cách nào để gọi câu lệnh này từ ADO.Net?

Mã Persistence của tôi (tin nhắn và tin nhắn Người nhận là DataTable):

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);
}

Tôi sử dụng SQLite (phiên bản ADO.Net)
Dabblernl

Câu trả lời:


88

Với SQL Server, bạn sẽ CHỌN SCOPE_IDENTITY () để nhận giá trị nhận dạng cuối cùng cho quy trình hiện tại.

Với SQlite, có vẻ như đối với một tự động gia tăng bạn sẽ làm

SELECT last_insert_rowid()

ngay sau khi bạn chèn.

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

Để trả lời nhận xét của bạn để nhận được giá trị này, bạn muốn sử dụng mã SQL hoặc OleDb như:

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
Cám ơn bạn một lần nữa! Rất tiếc, nó không hoạt động vì hàm last_insert_rowid () cần được gọi trước khi kết nối được sử dụng để cập nhật DataTable bị đóng. Đây có thể là một điều không minh bạch của SQLite dù ...
Dabblernl

1
Xin lỗi, có lẽ đó là sự thật. Bạn đã thử thực hiện nó sau các messagesAdapter.Update (các tin nhắn);
MikeW

2
@Dabblernl dường như câu trả lời khác là đáng tin cậy hơn, bạn có thể muốn thay đổi câu trả lời được chấp nhận nếu bạn cảm thấy một số khác là hữu ích hơn
MikeW

Nhưng RowId không phải lúc nào cũng giống như PRIMARY KEY. Ngoại trừIf the table has a column of type INTEGER PRIMARY KEY then that column is another alias for the rowid.
Кое Кто

110

Một lựa chọn khác là xem bảng hệ thống sqlite_sequence. Cơ sở dữ liệu sqlite của bạn sẽ tự động có bảng đó nếu bạn tạo bất kỳ bảng nào có khóa chính tự động tăng. Bảng này dành cho sqlite để theo dõi trường autoincrement để nó không lặp lại khóa chính ngay cả sau khi bạn xóa một số hàng hoặc sau khi một số lần chèn không thành công (đọc thêm về trường này tại đây http://www.sqlite.org/autoinc .html ).

Vì vậy, với bảng này, có thêm lợi ích là bạn có thể tìm ra khóa chính của mục mới được chèn ngay cả sau khi bạn đã chèn thứ khác (tất nhiên là trong các bảng khác!). Sau khi đảm bảo rằng việc chèn của bạn thành công (nếu không, bạn sẽ nhận được một số sai), bạn chỉ cần thực hiện:

select seq from sqlite_sequence where name="table_name"

1
Nó hoạt động khi trình tự được tăng dần và sau khi xóa hàng.
Marek Bar

Câu trả lời tốt. Kỳ lạ là trong "Trình duyệt DB cho SQLite" nếu xóa một hàng khỏi "sqlite_sequence", bạn sẽ không nhận được id cuối cùng cho một số bảng nữa.
CoolMind

8

Tôi gặp vấn đề với việc sử dụng SELECT last_insert_rowid() trong môi trường đa luồng. Nếu một luồng khác chèn vào một bảng khác có autoinc, last_insert_rowid sẽ trả về giá trị autoinc từ bảng mới.

Đây là nơi họ nói rằng trong doco:

Nếu một luồng riêng biệt thực hiện một INSERT mới trên cùng một kết nối cơ sở dữ liệu trong khi hàm sqlite3_last_insert_rowid () đang chạy và do đó thay đổi rowid chèn cuối cùng, thì giá trị được trả về bởi sqlite3_last_insert_rowid () là không thể đoán trước và có thể không bằng giá trị cũ hoặc mới chèn rowid.

Đó là từ sqlite.org doco


1
Tôi đoán bạn có thể sử dụng một kết nối riêng biệt cho từng luồng, nhưng tôi nhận thấy rằng nó có hiệu suất lớn. Tôi chỉ có thể thực hiện khoảng 15 lần chèn mỗi giây trong kịch bản của mình.
Fidel

Tôi đoán rằng các chủ đề riêng biệt sẽ là cùng một vấn đề. Thật không may cho đến nay dường như không có một công việc an toàn về chuỗi, linh cảm của tôi là nhiều giao dịch thậm chí sẽ không đủ ... vì vậy hãy cẩn thận: |
rogerdpack

5

Mã mẫu từ giải pháp @polyglot

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

4

Theo Android Sqlite lấy id hàng chèn cuối cùng có một truy vấn khác:

SELECT rowid from your_table_name order by ROWID DESC limit 1

1
Tùy chọn này có một hình phạt hiệu suất do thực hiện một thuật toán sắp xếp trước khi tìm ra rowid
Sr Libre

2
Có thể nó kém tối ưu hơn, nhưng nó thực sự hoạt động sau khi kết nối đã được đóng và mở lại, và hai giải pháp khác không phù hợp với tôi.
Francine DeGrood Taylor

Các biến thể sau đây tránh ORDER BY. Sẽ nhanh hơn, nhưng tôi đã không kiểm tra điều đó:SELECT MAX(rowid) FROM your_table_name
tanius
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.