How can I create a insert trigger in sqlite? I should check if the number of rows is < 5 = ok. If the number of rows is 5 = delete first row.
Is this way of collecting garbage efficient?
The documentation is quite good: http://www.sqlite.org/lang_createtrigger.html
You should end up with something like
CREATE TRIGGER rowlimit5
AFTER INSERT ON table
BEGIN
DELETE FROM table WHERE ROWID NOT IN (
SELECT ROWID FROM table ORDER BY ROWID DESC LIMIT 5
);
END;
Related
I'm using sqlite3 as a caching tool for an android app.
Basically, a services fetches data from a server at a regular interval and inserts the new records inside a sqlite3 table. The data is then used to populate UI inside activities and fragments.
Because the data is short-lived, it does not need to be persisted long-term.
In order to save space and resources, how can I make sure that say, only the 100 most recent records are kept and older entries are automatically deleted ?
I've heard of TRIGGERS but not too sure about how to implement them. Any pointers would be appreciated.
Follow the steps
1) Add one column in your table "timestamp"
2) During insert the record set the "timestamp" with current time in milliseconds.
3) Create Trigger like this
CREATE TRIGGER yourtriggername AFTER INSERT
ON yourtable WHEN (SELECT COUNT(*) FROM yourtable) >100
BEGIN
DELETE FROM yourtable WHERE timestamp = (SELECT MIN(timestamp) FROM yourtable)
END
4) Replace "yourtable" with actual table name
5) The above trigger will called every time and check whether the total records in table exceeds 100 it will remove the record whose "timestamp" is minimum.
select entry_id
from entries
order by create_date desc
limit 1 offset 100;
delete from entries where create_date <
(select create_date from entries where entry_id = obtained_entry_id);
Or just:
delete from entries where create_date <
(select create_date from entries by create_date desc limit 1 offset 100);
Trigger to enforce it:
CREATE TRIGGER truncate_entries AFTER INSERT ON entries
BEGIN
--the delete statement from above
END;
Anyone know of a way to limit the number of rows deleted when using an sql DELETE statement?I just need to delete a row that holds a certain value one time instead of deleting every instance of the value. It's my understanding that the LIMIT clause cannot be added to DELETE statements in SQLITE. Now, I can't see a way to limit the number of rows deleted just using _id because I don't know what row _id will be deleted ahead of time; the rows are being deleted based on a value held in a variable and they could be anywhere in the DB. I hope this makes sense. Here's the delete statement:
String sql = "DELETE FROM strategyTotal WHERE strategy_prices = (?)" ;
db.execSQL(sql, new Double[] {subtractedStrategyPrice });
Use a subquery:
String sql = "DELETE FROM strategyTotal WHERE _id IN (SELECT _id FROM strategyTotal WHERE strategy_prices = (?) LIMIT 1);" ;
db.execSQL(sql, new Double[] {subtractedStrategyPrice });
delete from tablename where rowid in (
select rowid from tablename condition LIMIT 1)
try above work around or you may need to enable SQLITE ENABLE UPDATE DELETE LIMIT
my query is just an example. replace it with your own query.
It's possible create on SQLite a "complex" trigger? for complex i mean that trigger body should provide to count row inside a table, then if count it's greater than a fixed value, delete some rows for satisfy previuos condition
You should be able to do that using the WHERE clause of the trigger definition, eg WHERE count(*>100. Then in the action part of the trigger, define a DELETE statement with a WHERE clause that identifies which "oldest" entry you want to delete.
Assuming that ID is an autoincrementing column, the following query would find those records with the 100 highest ID values, i.e., those that should not be deleted:
SELECT *
FROM MyTable
ORDER BY ID DESC
LIMIT 100
This allows to write the following trigger:
CREATE TRIGGER DeleteOldestMoreThan100
AFTER INSERT ON MyTable
-- WHEN (SELECT COUNT(*) FROM MyTable) > 100 -- not needed
BEGIN
DELETE FROM MyTable
WHERE ID NOT IN (SELECT ID
FROM MyTable
ORDER BY ID DESC
LIMIT 100);
END;
I use this method to delete a row in my sqlite db:
db.execSQL("delete from "+TABLE_NUMS+" where _ID = '" + this.rowID + "'");
and then I update the rest of Ids to make my entries consecutive:
db.execSQL("UPDATE "+TABLE_NUMS+" set _ID = (_ID - 1) WHERE _ID > "+this.rowID);
And it works fine, but when I add new entries to my DB, the ID of the new entries still add as if the deleted entries existed, say I have 10 rows with IDs starting from 1 to 10, and then I delete number 5 and 6, the rows become 1 to 8, but the new entry's ID will be 11. So my IDs sequence would be 1 to 8 and 11. How can I fix this?
SQLite keeps track of the largest ROWID that a table has ever held using the special SQLITE_SEQUENCE table. You cam modify that sequence as:
UPDATE SQLITE_SEQUENCE SET seq = this.ID -1 WHERE name = TABLE_NUMS
The same functionality is asked in this question.
The normal ROWID selection algorithm described above will generate
monotonically increasing unique ROWIDs as long as you never use the
maximum ROWID value and you never delete the entry in the table with
the largest ROWID. If you ever delete rows or if you ever create a row
with the maximum possible ROWID, then ROWIDs from previously deleted
rows might be reused when creating new rows and newly created ROWIDs
might not be in strictly ascending order.
http://www.sqlite.org/autoinc.html
This is how SQLite works.
If you really need to have the Ids consecutive don't use autoincrement.
Insert the ids yourself.
You can select MAX(_ID) first to get the last id (greatest value).
This is because you have autoincrement set on _ID when you created the table. So, every row you add will be given a number automatically unless you explicitly set it. If it is absolutely necessary that you need the _IDs in consecutive order, I recommend that you set it yourself instead of using autoincrement.
Here is how to reset it:
delete from your_table;
delete from sqlite_sequence where name='your_table';
This will delete all your data and reset the sequence.
SQLite keeps the largest ROWID in the special SQLITE_SEQUENCE table. You can update that table as:
db.execSQL("UPDATE SQLITE_SEQUENCE SET seq = 0 WHERE NAME = '"+TABLE_NAME+"'");
OR
delete that table as:
db.delete("SQLITE_SEQUENCE","NAME = ?",new String[]{TABLE_NAME});
I have a sqlite db that at the moment has few tables where the biggest one has over 10,000 rows. This table has four columns: id, term, definition, category. I have used a FTS3 module to speed up searching which helped a lot. However, now when I try to fetch 'next' or 'previous' row from table it takes longer than it was before I started using FTS3.
This is how I create virtual table:
CREATE VIRTUAL TABLE profanity USING fts3(_id integer primary key,name text,definition text,category text);
This is how I fetch next/previous rows:
SELECT * FROM dictionary WHERE _id < "+id + " ORDER BY _id DESC LIMIT 1
SELECT * FROM dictionary WHERE _id > "+id + " ORDER BY _id LIMIT 1
When I run these statements on the virtual table:
NEXT term is fetch within ~300ms,
PREVIOUS term is fetch within ~200ms
When I do it with normal table (the one created without FTS3):
NEXT term is fetch within ~3ms,
PREVIOUS term is fetch within ~2ms
Why there is such a big difference? Is there any way I can improve this speed?
EDITED:
I still can't get it to work!
Virtual table you've created is designed to provide full text queries. It's not aimed to fast processing standard queries using PK in where condition.
In this case there is no index on your _id column, so SQLite probably performs full table scan.
Next problem is your query - it's totally inefficient. Try something like this (untested):
SELECT * FROM dictionary WHERE _id = (select max(_id) from dictionary where _id < ?)
Next thing you can consider is redesign of your app. Instead of loading 1 row you, maybe you should get let's say 40, load them into memory and make background data loading when there is less than n to one of the ends. Long SQL operation will become invisible to user even if it'll last 3s instead of 0,3s
If you're running LIMIT 1 to begin with, you can remove the order by clause completely. This may help. I'm not familiar with FTS3, however.
You could also just flat out assign your id variable a ++ or -- and assert `WHERE _id = "+id+" LIMIT 1" which would make a single lookup instead of < or >.
Edit: and now that I look back at what I typed, if you do it that way, you can just remove LIMIT 1 completely, since your _id is your pk and must be unique.
hey look, a raw where clause!