Delete records which have more than N entries - sqlite

I have a table called history,
which has three columns.
id, value, timestamp
Id is not a primary key, but the pair (id, timestamp) is unique.
What I would like to do is delete all the older records for a specific ID that exceed a certain limit.
For example if i have these values:
-1,value1,1
-1,value2,2
-1,value3,3
-2,value4,4
-2,value5,5
-2,value6,6
And the limit is 2. After executing the statement i should get something like:
-1,value2,2
-1,value3,3
-2,value4,4
-2,value5,5
-2,value6,6

I think I have it (tried and works for the testcases i had), the answer is:
DELETE FROM history WHERE id = ?1 AND timestamp NOT in (SELECT sourcetime FROM history WHERE id =?1 ORDER BY timestamp DESC LIMIT ?2);

DELETE FROM ... WHERE timestamp < ...
Doesn't work ?

Related

SQL error or missing database (near "," syntax error)

I have this query with syntax error. Can you help me find the error please?
I spend couple of hour and I can't solve it. Thanks.
String sql = " INSERT INTO appointments (patient_firstname, patient_surname, fees, time, date, doctor)"
+ " SELECT (time, date, doctor)"
+ " WHERE NOT EXISTS (SELECT * FROM appointments WHERE time = ?)";
pst=conn.prepareStatement(sql);
pst.setString(1,txt_firstname.getText());
pst.setString(2,txt_surname.getText());
pst.setString(3, txt_fee.getText());
pst.setString(4, (String) cbox_time.getSelectedItem());
pst.setString(5,txt_date.getText());
pst.setString(6, (String) cbox_doctors.getSelectedItem());
pst.executeUpdate();
The issues with your INSERT statement includes :-
You appear to be attempting an INSERT SELECT where the VALUES to be inserted are obtained from the SELECT clause, but you are trying to mix this with VALUES. The two types cannot be combined.
You are trying to select using columns within parenthesises and anyway those three columns WILL NOT match the 6 columns required for the insert.
You only have 1 ? to be bound, you are trying to bind 6.
I'd suggest that you could simplify matters by defining the table with a UNIQUE constraint on the doctor, date and time columns. Then use a standard INSERT OR IGNORE with the VALUES clause.
e.g. consider the following demonstration SQL :-
DROP TABLE IF EXISTS appointments;
CREATE TABLE IF NOT EXISTS appointments (patient_firstname TEXT, patient_surname TEXT, fees REAL, time TEXT, date TEXT, doctor INTEGER, UNIQUE (doctor, date, time));
INSERT OR IGNORE INTO appointments VALUES ('Fred','Bloggs',100.50,'10:00','2019-01-01',1);
INSERT OR IGNORE INTO appointments VALUES ('Mary','Smith',100.50,'10:00','2019-01-01',2);
INSERT OR IGNORE INTO appointments VALUES ('Sue','Bell',100.50,'10:00','2019-01-01',2);
SELECT * FROM appointments;
This results in :-
i.e Sue Bell's appointment has not been added because of the UNIQUE constraint conflict, which has been ignored so there is no error.
The log being :-
DROP TABLE IF EXISTS appointments
> OK
> Time: 0.177s
CREATE TABLE IF NOT EXISTS appointments (patient_firstname TEXT, patient_surname TEXT, fees REAL, time TEXT, date TEXT, doctor INTEGER, UNIQUE (doctor, date, time))
> OK
> Time: 0.084s
INSERT OR IGNORE INTO appointments VALUES ('Fred','Bloggs',100.50,'10:00','2019-01-01',1)
> Affected rows: 1
> Time: 0.083s
INSERT OR IGNORE INTO appointments VALUES ('Mary','Smith',100.50,'10:00','2019-01-01',2)
> Affected rows: 1
> Time: 0.084s
INSERT OR IGNORE INTO appointments VALUES ('Sue','Bell',100.50,'10:00','2019-01-01',2)
> Affected rows: 0
> Time: 0s
SELECT * FROM appointments
> OK
> Time: 0.003s

sqlite shift rowid in multiple records

Hello i have an sqlite db with many records like 10540 record they are ordered by creation time , i want to shift like a record in the middle and like to do it automatically
for example :
select * from table1 where id >= 8521;
UPDATE Table1 SET id = id +1 ;
does not work i get Error: Result: UNIQUE constraint failed:
so i want to shift up all records from 8521 to the last record and get place in the 8520 place for example so i can insert my record in that place of table .
even the
id = select max(id)+1
does not work how can i increment the id from last record to the needed record so i can put a place in the records db
A simple update statement would fail, as it would try to create duplicate values in the primary key.
What you can do is this:
First update the column to the negatives of the values they should have:
update table1
set id = -(id + 1)
where id > 8520;
Now there are no duplicates and you just need to update again to the positive values:
update table1
set id = -id
where id < 0;
This will do the trick, but any kind of updating the primary key is not a recommended practice

Update Query with limit cause SQLite

i have table in SQLite named TBL_data
i have two fields id and name
All id is set to the -1
i want to update first occurrence of record
for this i have used
update TBL_data set name = 'XYZ' where id = -1 limit 1
it shows error, is there any other way ?
That query works only if you have compiled SQLite with SQLITE_ENABLE_UPDATE_DELETE_LIMIT.
If this is not the case, you have to use some unique key of your table to determine the rows:
UPDATE tbl_data
SET ...
WHERE rowid IN (SELECT rowid
FROM tbl_data
WHERE ...
ORDER BY ...
LIMIT 1)

How to "update" the _id column in SQLite Database Browser

The _id column in my database is an INTEGER PRIMARY KEY, so it is an auto-incrementing column.
The problem is that now I deleted a row, and the column didn't update the auto-incrementing number.
Is there a way to make the _id column update, so there wouldn't be holes in the sequence?
Thank you very much in advance.
No. This is not how it is intended to be used. Don't mess with the primary key! There will be gapes. The id is just a unique identifier.
If you need a rank then you can do that
select t.*, #rank := #rank + 1 as gapless_rank
from your_table t
cross join (select #rank := 0) r
order by id
To get the nth ID from the table, use a query like this:
SELECT _id
FROM MyTable
ORDER BY _id
LIMIT 1
OFFSET n-1

SQLITE fill value with unique random table

I want to create a table with a field that is unique and limited to a certain value. Lets say that the limit is 100, the table is full, I remove a random row, and when I create a new row it has the value that was freed before.
It doesn't need to be the fastest thing in the world (the limit is quite small), I just want to implement it in a DB.
Any ideas?
Create one more column in main table, say deleted (integer, 0 or 1). When you need to delete with certain id, do not really delete it, but simply update deleted to 1:
UPDATE mytable SET deleted=1 WHERE id = <id_to_delete>
When you need to insert, find id to be reused:
SELECT id FROM mytable WHERE deleted LIMIT 1
If this query returns empty result, then use INSERT to create new id. Otherwise, simply update your row:
UPDATE mytable SET deleted=0, name='blah', ... WHERE id=<id_to_reuse>
All queries reading from your main table should have WHERE constraint with NOT deleted condition:
SELECT * FROM mytable WHERE NOT deleted
If you add index on deleted, this method should work fast even for large number of rows.
This solution does everything in a trigger, so you can just use a normal INSERT.
For the table itself, we use an autoincrementing ID column:
CREATE TABLE MyTable(ID INTEGER PRIMARY KEY, Name);
We need another table to store an ID temporarily:
CREATE TABLE moriturus(ID INTEGER PRIMARY KEY);
And the trigger:
CREATE TRIGGER MyTable_DeleteAndReorder
AFTER INSERT ON MyTable
FOR EACH ROW
WHEN (SELECT COUNT(*) FROM MyTable) > 100
BEGIN
-- first, select a random record to be deleted, and save its ID
DELETE FROM moriturus;
INSERT INTO moriturus
SELECT ID FROM MyTable
WHERE ID <> NEW.ID
ORDER BY random()
LIMIT 1;
-- then actually delete it
DELETE FROM MyTable
WHERE ID = (SELECT ID
FROM moriturus);
-- then change the just inserted record to have that ID
UPDATE MyTable
SET ID = (SELECT ID
FROM moriturus)
WHERE ID = NEW.ID;
END;

Resources