SQLite: How to limit the number of rows based on the timestamp?
-
24-06-2021 - |
Question
I successfully used the following BEFORE INSERT
trigger to limit the number of rows stored in the SQLite database table locations. The database table acts as a cache in an Android application.
CREATE TRIGGER 'trigger_locations_insert'
BEFORE INSERT ON 'locations'
WHEN ( SELECT count(*) FROM 'locations' ) > '100'
BEGIN
DELETE FROM 'locations' WHERE '_id' NOT IN
(
SELECT '_id' FROM 'locations' ORDER BY 'modified_at' DESC LIMIT '100'
);
END
Meanwhile, I added a second trigger that allows me to INSERT OR UPDATE
rows. - The discussion on that topic can be found in another thread. The second trigger requires a VIEW
on which each INSERT
is executed.
CREATE VIEW 'locations_view' AS SELECT * FROM 'locations';
Since an INSERT
is no longer executed on the TABLE
locations but on the VIEW
locations_view, the above trigger does no longer work. If I apply the trigger on the VIEW
the following error message is thrown.
Failure 1 (cannot create BEFORE trigger on view: main.locations_view)
Question:
How can I change the above trigger to observe each INSERT
on the VIEW
- or do you recommend another way to limit the number of rows? I would prefer to handle this kind of operation within the database, rather then running frontend code on my client.
Performance issues:
Although, the limiter (the above trigger) works in general - it performs less then optimal! Actually, the database actions take so long that an ANR is raised. As far as I can see, the reason is, that the limiter is called every time an INSERT
happens. To optimize the setup, the bulk INSERT
should be wrapped into a transaction and the limiter should perform right after. Is this possible? If you like to help, please place optimization comments concerning the bulk INSERT
into the original question. Comments regarding the limiter are welcome here.
La solution
This type of trigger should work fine in conjunction with the other one. The problem appears to be that the SQL is unnecessarily quoting the _id
field. It is selecting the literal string "_id" for every row and comparing that to the same literal string.
Removing the quotes around '_id'
(both in the DELETE
and in the sub-SELECT
) should fix the problem.