如何按行順序獲取缺失值?
在一個表中,許多行已被刪除,如何獲取下一個缺失行的 id
INSERT
?例如
id col1 1 1 3 3 4 4 5 5 8 8 9 9
如何獲得 next 的第一個可用 id 的值
INSERT
。在這裡我想得到id = 2
.就像是
SELECT id+1 FROM table WHERE CLAUSE // pointing to the least available value // or x = id +1 (after SELECT) INSERT INTO table (id, ....) VALUES ('x', ....)
如果該列只是一個代理鍵並且不用於其他目的(顯示排序等),那麼我將只使用您的數據庫的
AUTOINCREMENT
等效項並忽略 ID 中存在間隙的事實,因為點是唯一的而不是服務於其他目的。備受推薦的“SQL Anti-Patterns”一書中有一章題為“pseudokey quiet-freak”。這取決於您要建模的內容以及當然,如果數字確實具有超出標識符的含義,那麼這一點是無關緊要的。您想要閱讀的一般概念(值得閱讀一些背景知識,因為這些問題隨處可見,因此知道如何發現它們並有效地處理它們或設計它們非常有用)是gaps 和 island。有很多關於此的線上參考資料(這是快速搜尋發現的第一個,它是在談論 MSSQL,但概念是可以轉移的)。
除了
WHERE NOT EXISTS
通常建議的方法,因為程式碼讀取的方式使您的意圖更加明顯,您還可以執行以下操作:SELECT TOP 1 t1.id-1 FROM yourtable t1 LEFT OUTER JOIN yourtable t2 ON t2.id=t1.id-1 -- will match if there is a row with the next ID down from the row in t1 WHERE t2.id IS NULL -- the next ID down not found AND t1.id > 0 -- assume 1 is the lowest valid ID ORDER BY t1.id
(即 MSSQL 語法,您可能需要對其進行調整)
兩種變體都應產生相似的查詢計劃,因此執行相同,但我已經看到上述方法作為更複雜查詢的一部分錶現更好,因此可能值得嘗試兩者您的情況並驗證哪個表現最佳。
如果表為空,也不是目前提供的任何方法都不會返回第一個 ID:您將不會返回任何行(如果您將其用作子查詢,則返回 NULL)。解決此問題的一種方法是使用“無效”行,
id=0
但這很髒(您最終不得不從許多其他查詢中過濾掉它),因此強烈建議您改為處理邏輯中的空/NULL。對於在生產中永遠不會為空的表(例如,使用者表,即使在初始安裝時,初始設置/管理員使用者也會有一條記錄),這或當然不是問題。*編輯:*更正查詢以在未找到時返回第一個 ID,因為 ypercube 指出第一個版本不會這樣做
較新的 mySQL 版本
從這個答案開始,mySQL 和 MariaDB 增加了對視窗函式的支持(分別在版本 8 和 10.2 中),例如
LAG()
和LEAD()
. 您可以使用這些來檢查下一行(或上一行)並比較打算增加的值並查看是否存在間隙,這意味著您不需要將表連接到自身或EXISTS
為此使用子查詢比較 - 使用正確的索引,這可能是一種更有效的方式來實現一些間隙/孤島查詢。所有常見的 SQL 數據庫引擎(sqlite、postgres、SQL Server、Oracle 等)現在都支持視窗函式。