2014-09-26 5 views
4

У меня есть ситуация, когда я просто хочу ограничить только 50 строк в таблице. Если пользователь вставляет новую строку после этого, то первая строка (которая была вставлена ​​очень первой) должна быть удалена, а новая строка вставлена, так что счетчик останется таким же. Я знаю, что у меня может быть поле rowid и при вставке новой записи я могу проверить, есть ли уже 50 строк, чтобы удалить самый маленький rowid, а затем вставить новый. Но просто хочу знать, есть ли лучшее решение, так что мне не нужно делать 3 операции с базой данных (1. запрос # из строк, 2. удалить минимум, 3. вставить)Ограничение количества строк в SQLite

+0

Вы могли бы рассмотреть триггер после вставки, чтобы удалить все строки с 'ROWID <= (макс (ROWID) - 50)' – ssnobody

+0

@ssnobody Это взорвется, когда 'rowid's не являются непрерывными. –

+0

Как бы вы запрашивали количество строк или удаляли какую-либо старую строку без операции с базой данных? Эти действия являются, по определению, операциями в базе данных. –

ответ

1

Я знаю способ, который работает, но это немного уродливо. Он опирается на тщательно сконструированные ограничения и на посев базы данных. Для краткости я использую только пять строк вместо 50.

create table test (
    row_num integer primary key 
    check ((round(row_num) = row_num) and (row_num between 1 and 5)), 
    other_columns char(1) not null default 'x', 
    row_timestamp timestamp 
    not null unique 
    default current_timestamp 
); 

Выражение round(row_num = row_num) гарантирует у вас есть целые числа в столбце ROW_NUM. В противном случае SQLite позволит вам вставлять 1,54 или «wibble».

Столбец other_columns - это просто место для ваших фактических данных.

insert into test (row_num, row_timestamp) values 
(1, '2015-01-01 08:00:01'), 
(2, '2015-01-01 08:00:02'), 
(3, '2015-01-01 08:00:03'), 
(4, '2015-01-01 08:00:04'), 
(5, '2015-01-01 08:00:05'); 

Фактические значения временной метки на самом деле ничего не означают. Во всяком случае, пока нет. Выделение базы данных, как это, означает, что отныне вы должны выполнять только инструкции обновления. Если таблица была пуста для начала, вам придется иметь дело с другой логикой для вставок и обновлений. Например, вам нужно будет подсчитать строки, чтобы выяснить, следует ли вставлять или обновлять.

create trigger update_timestamp 
after update on test 
for each row 
begin 
    update test 
    set row_timestamp = strftime('%Y-%m-%d %H:%M:%f', 'now') 
    where row_num = OLD.row_num; 
end; 

Триггер "update_timestamp" делает SQLite поддерживать временную метку с долей секунды (%f). Возможно, зависит от того, поддерживает ли базовая ОС дробную точность.

create trigger no_deletes 
after delete on test 
for each row 
begin 
    -- There might be a more elegant way to prevent deletes. 
    -- This way just inserts exactly what a delete statement deletes. 
    insert into test (row_num, other_columns, row_timestamp) 
    values (OLD.row_num, OLD.other_columns, OLD.row_timestamp); 
end; 


Теперь вы можете обновить данные. Вы обновляете свои собственные данные, которые здесь являются только заполнителем other_columns, а SQLite заботится обо всем остальном.

update test 
set other_columns = 'b' 
where row_timestamp = (select min(row_timestamp) from test); 
select * from test order by row_timestamp desc; 
 
row_num  other_columns row_timestamp   
---------- ------------- ----------------------- 
1   b    2015-03-08 12:43:21.926 
5   x    2015-01-01 08:00:05  
4   x    2015-01-01 08:00:04  
3   x    2015-01-01 08:00:03  
2   x    2015-01-01 08:00:02 
Смежные вопросы