2012-08-01 47 views
3

我先做了一些搜索,但仍然有一個問題。在SQLite表中檢索最後的記錄(再次)

不久之後,我發現的最佳答案是在this SO回答。總結:

SELECT * FROM TABLE WHERE ID = (SELECT MAX(ID) FROM TABLE);

我想知道的是,如果下面的方法一樣好(因爲我懶得去改變它,我碰巧喜歡它)。

SELECT * FROM TABLE ORDER BY ID DESC LIMIT 1

按照SQLite Autoincrement文檔,我們有,

如果在插入指定ROWID,或者指定的ROWID具有NULL值,然後適當的ROWID會自動創建。 通常的算法是在插入之前爲新創建的行提供比表中最大ROWID大一個的ROWID。如果表格最初是空的,則使用1的ROWID。 [強調]

,並進一步,

上述將產生只要單調遞增獨特的ROWID,你從來沒有使用最大ROWID值,你永遠不刪除該條目中的正常ROWID選擇算法帶有最大ROWID的表。 如果您曾經刪除過行,或者曾經創建過可能具有最大ROWID的行,那麼創建新行時可能會重複使用先前刪除的行中的ROWID,並且新創建的ROWID可能不會嚴格按升序排列。 [加重點]

我對我提出的SQL語句的問題來自最後一句。它似乎表明,如果刪除任何行,則可以重新使用先前刪除的ROWID,而不管最大ROWID是否已被使用。如果我們假設從未使用過最大ROWID(無論是手動還是隻有那麼多記錄),那麼我們只需要擔心刪除記錄。在這種情況下,第一個SQLite文檔摘錄使它聽起來像你不會遇到任何問題與我的查詢。

有誰知道嗎?

我喜歡我的查詢,因爲它只涉及一個select(albiet,代價是訂單)。我想,我可能過分關注微小的優化,是不是?

編輯: 其實,重新審查上面引用的SQLite頁面,我認爲使用AUTOINCREMENT關鍵字可以保證單調遞增的ROWID。最後一節詳細討論了這一點。

如果列的類型爲INTEGER PRIMARY KEY AUTOINCREMENT,則使用稍微不同的ROWID選擇算法。爲新行選擇的ROWID至少比之前在同一個表中存在的最大ROWID大一個。如果表中以前從未包含任何數據,則使用1的ROWID。如果該表先前已經保留了一個具有最大可能ROWID的行,那麼不允許新的INSERT,並且任何插入新行的嘗試都將失敗,並出現SQLITE_FULL錯誤。

現在似乎很清楚。只是不能填滿表格(最大9223372036854775807)。

對不起,我只是早些時候剔除了這部分!

+0

我沒有看到問題。你的邏輯對我來說很合理。重新使用ROWID的想法似乎是優化表空間和偏移量。 – 2012-08-01 19:40:23

+0

如果您想保證選擇最後一行的方法,請使用時間戳而不是'ROWID'。 (假設你沒有及時出行或將系統時鐘設置爲過去) – Sam 2012-08-01 19:42:08

+0

@Sam可能會比我的方法更好,因爲使用Autoincrementing rowid字段會使插入速度變慢。雖然,對於大多數應用程序,我敢打賭,這並不重要。 – CatShoes 2012-08-01 19:59:51

回答

3

您顯示的兩個查詢是等效的。

至於他們是否返回最後的記錄,這取決於你的意思是「最後」。如果刪除行,則不能依賴任何查詢返回最後插入的行。

+0

請參閱我的編輯問題。我認爲,通過正確聲明的字段,他們可以確保返回插入的最後一行。即使存在刪除的行,除非我誤解了最後的引用。 – CatShoes 2012-08-01 19:47:49

+1

是的,如果你使用'AUTOINCREMENT',你會得到最後一個插入的行。 – 2012-08-01 19:56:24

+0

謝謝!只是想在我實施之前確定。 – CatShoes 2012-08-01 19:58:03

3

想象一下,我會在這裏提一下關於兩個查詢運行速度的信息。
在有大約15,000行的表,抓住他們的1400,然後讓最後輸入的一個,這裏是什麼結果我:

SELECT macAddr, time, onPeakTotalIn, onPeakTotalOut, offPeakTotalIn, offPeakTotalOut FROM trafficMon WHERE macAddr="02:d2:ee:aa:aa:aa" ORDER BY time DESC LIMIT 1; 

CPU時間:用戶0.008124 SYS 0.000000
虛擬機步驟:58741
全掃描步驟:14156

SELECT macAddr, time, onPeakTotalIn, onPeakTotalOut, offPeakTotalIn, offPeakTotalOut FROM trafficMon WHERE id = (SELECT MAX(id) FROM trafficMon WHERE macAddr="02:d2:ee:aa:aa:aa"); 

CPU時間:用戶0.000295 0.000000 SYS
虛擬機步驟:49
Fullscan步驟:3

正如您所看到的,明智地執行MAX(id)資源並且花費更少的時間來執行操作會容易得多。

儘管0.008124s一直都是bugger,但當你在基於MIPS的嵌入式設備(在我的情況下是路由器)上運行相同的命令時,它會在腳本中運行20-30x以及其他一些東西,全部加起來。

希望這有助於:)

鴨子

1

,首先你應該檢索最後插入的行ID然後你可以通過你的選擇查詢得到最後插入該行的ID。

RowID = sqlite3_last_insert_rowid(sqlite3Database) 

SELECT * FROM tableName where RowID=RowID 

此select語句會給你一個最後插入的記錄

this link.

+2

儘管這個鏈接可能回答這個問題,但最好在這裏包含答案的基本部分,並提供參考鏈接。如果鏈接頁面更改,則僅鏈接答案可能會失效。 – MZaragoza 2015-01-11 05:53:50

+0

是的,你是對的@MZaragoza現在我試圖清除我的答案,謝謝你的建議。 – 2015-01-11 06:09:28

1

如果表中有一個字段類型「自動增量」得到更多的細節,則是更好地使用:

SELECT seq FROM sqlite_sequence WHERE name='TABLE_NAME' 

查看樣本(對於'客戶'表):

SELECT seq FROM sqlite_sequence WHERE name='customers'