2009-12-29 18 views
10

我想創建一個不超過n行數據的SQL表。當插入一個新行時,我想刪除最舊的行以騰出空間給新的行。SQL表中的滾動行

有沒有一種在SQLite中處理這個問題的典型方法?

應該用一些外部(第三方)代碼來管理它嗎?

回答

11

擴展在Alex' answer,假設你有一個遞增的,不重複的命名serialt可以用來確定行的相對年代序列列:

CREATE TRIGGER ten_rows_only AFTER INSERT ON t 
    BEGIN 
    DELETE FROM t WHERE serial <= (SELECT serial FROM t ORDER BY serial DESC LIMIT 10, 1); 
    END; 

,當你有少於十行,並將DELETE最低的串行時INSERT會推你到十一行。這會什麼都不做。

UPDATE

這裏有一個稍微複雜一點的情況下,你的表記錄中可能包含重複,例如一個TIMESTAMP列跟蹤插入時間一列列的「年齡」。

sqlite> .schema t 
CREATE TABLE t (id VARCHAR(1) NOT NULL PRIMARY KEY, ts TIMESTAMP NOT NULL); 
CREATE TRIGGER ten_rows_only AFTER INSERT ON t 
    BEGIN 
    DELETE FROM t WHERE id IN (SELECT id FROM t ORDER BY ts DESC LIMIT 10, -1); 
    END; 

在這裏,我們理所當然地認爲,我們不能用id確定相對年齡,所以我們通過時間戳訂購了第10行後刪除所有內容。 (SQLite在共享同一個ts的行上施加任意順序)。

+0

不會總是這樣刪除第一行? – aronchick

+0

@aronchick,no - 如果在第11個位置(可能是第11行的INSERT之後)沒有記錄,則標量子查詢將評估爲NULL,因此WHERE子句變爲WHERE serial <= NULL,這不會匹配任何東西。 – pilcrow

+0

如果_id是自動遞增的,該怎麼辦?無法用_id代替TIMESTAMP或串行來完成此代碼?特別是當TIMESTAMP並不總是表模式的一部分時... –

0

這將是如何你會這樣做。這假定my_id_column是自動遞增的,並且是該表的排序列。

-- handle rolls forward 
-- deletes the oldest row 
create trigger rollfwd after insert on my_table when (select count() from my_table) > max_table_size 
    begin 
    delete from my_table where my_id_column = (select min(my_id_column) from my_table); 
    end; 

-- handle rolls back 
-- inserts an empty row at the position before oldest entry 
-- assumes all columns option or defaulted 
create trigger rollbk after delete on my_table when (select count() from my_table) < max_table_size 
    begin 
    insert into my_table (my_id_column) values ((select min(my_id_column) from my_table) - 1); 
    end;