The ids of a table in my sqlite database have been reset - sqlite

I have an iPhone app and one of my users found a really strange problem with my application. I can't reproduce the problem and I can't figure out why it's happening. Maybe you can?
In Sqlite I have a table with about 1000 rows, each with a unique id. But for some reason the id of that table has restarted, before it was around 1000 but now it's restarted from 80 something. So everytime the user inserts a new row the new assigned id starts around 80 something and I get two duplicates ids that should be unique and yeah you can understand the problem. I have looked at all queries that does anything to that table and none of them could have done this. I always relay on the built in mechanism where the ids are assigned automatically.
Have you seen anything like this?
The schema of the table looks like this:
CREATE TABLE mytable(
id INTEGER PRIMARY KEY
);
As you can see I don't use AUTOINCREMENT. But from what I understand even if the user deletes a row with id 80, it is ok to give a new inserted row id 80 but not like it works now where the database just keeps incrementing the ids even if I have already have rows with the same id. Shouldn't it work like this:
HIGHEST ROWID IS 1000, ALL IDS FROM 0-1000 ARE TAKEN
USER DELETES ROW WITH ID 80
INSERT A NEW ROW
THE ID OF THE INSERTED ROW MIGHT NOW BE 80
SETS THE ID OF THE INSERTED ROW TO 80
INSERT A NEW ROW
THE ID OF THE INSERTED ROW CAN NOT BE 81 AS THIS IS ALREADY TAKEN
SETS THE ID OF THE INSERTED ROW TO 1001
Isn't that how it should work?

Did you declare your id column as a(n autoincrementing) primary key?
CREATE TABLE mytable(
id INTEGER PRIMARY KEY AUTOINCREMENT
);
By adding the autoincrement keyword you ensure that all keys generated will be unique over the lifetime of your table. By omitting it, the keys will still be unique, but it may generate keys that have already been used by other, deleted entries. Note that using autoincrement can cause problems, so read up on it before you add it.
Edit This is a bit of a long-shot, but sqlite only supports one primary key per table. If you have more than one primary key declared, you need to declare all but the one you actually want to use as a primary key as "unique". Hence
CREATE TABLE mytable(
id INTEGER PRIMARY KEY,
otherId INTEGER UNIQUE
);

Hard to say without the code and schema, but my instinct is that this unique ID is not defined as either unique nor primary key, which they should.
How do you make sure (in theory) id's are unique? What is your insert query like?

Related

SQLite Swap 2 Primary Key Values In A Column

My table student is as follows:
Name
Id
Dave
3414
Bob
2861
The ID is the primary key value that has a unique constraint. I'm trying to swap the two primary key values, so Bob's ID is 3414 and Dave's ID is 2861. What's the quickest way to do this?
UPDATE student SET Id=2861 WHERE Id=3414;
UPDATE student SET Id=3414 WHERE Id=2861;
These two statements won't work as it will create duplicate primary keys.
You can do it in three steps (Wrapped in a transaction so it's atomic as far as other connections to the database are concerned), by first changing one of the PKs to a value that's not already in the database. Negative numbers work well, assuming your PKs are normally values >= 0, which is true of automatically generated rowid/INTEGER PRIMARY KEY values in Sqlite.
BEGIN;
UPDATE student SET Id=-Id WHERE Id=2861;
UPDATE student SET Id=2861 WHERE Id=3414;
UPDATE student SET Id=3414 WHERE Id=-2861;
COMMIT;
Somebody asked something like this here
but it apparently does not work in some versions

How to continue from the last id in sqlite db? (includes recyclerview)

As you know well if i delete entries from a db or completely clear that db, id is autoincremented from where it is left. How can I prevent this- I mean I want my database dont erase the last id's for example even id=2 is removed next id should be id=3. thanks
Declare your id field INTEGER PRIMARY KEY AUTOINCREMENT. That should prevent re-use of id values. (See https://sqlite.org/autoinc.html)

Insert or ignore every column

I have a problem with a sqlite command.
I have a table with three columns: Id, user, number.
The id is continuing. Now if I put a user and a number inside my list, my app should compare if such a user with this number already exist. The problem is, if I use a standard "insert or ignore" command, the Id column is not fixed, so I will get a new entry every time.
So is it possible just two compare two of three columns if they are equal?
Or do I have to use a temporary list, where are only two columns exist?
The INSERT OR IGNORE statement ignores the new record if it would violate a UNIQUE constraint.
Such a constraint is created implicitly for the PRIMARY KEY, but you can also create one explicitly for any other columns:
CREATE TABLE MyTable (
ID integer PRIMARY KEY,
User text,
Number number,
UNIQUE (User, Number)
);
You shouldn't use insert or ignore unless you are specifying the key, which you aren't and in my opinion never should if your key is an Identity (Auto number).
Based on User and Number making a record in your table unique, you don't need the id column and your primary key should be user,number.
If for some reason you don't want to do that, and bearing in mind in that case you are saying that User,Number is not your uniqueness constraint then something like
if not exists(Select 1 From MyTable Where user = 10 and Number = 15)
Insert MyTable(user,number) Values(10,15)
would do the job. Not a SqlLite boy, so you might have to rwiddle with the syntax and wrap escape your column names.

SQLite: Ordering my select results

I have a table with unique usernames and a bunch of string data I am keeping track of. Each user will have 1000 rows and when I select them I want to return them in the order they were added. Is the following code a necessary and correct way of doing this:
CREATE TABLE foo (
username TEXT PRIMARY KEY,
col1 TEXT,
col2 TEXT,
...
order_id INTEGER NOT NULL
);
CREATE INDEX foo_order_index ON foo(order_id);
SELECT * FROM foo where username = 'bar' ORDER BY order_id;
Add a DateAdded field and default it to the date/time the row was added and sort on that.
If you absolutely must use the order_ID, which I don't suggest. Then at least make it an identity column. The reason I advise against this is because you are relying on side affects to do your sorting and it will make your code harder to read.
If each user will have 1000 rows, then username should not be the primary key. One option is to use the int identity column which all tables have (which optimizes I/O reads since it's typically stored in that order).
Read under "RowIds and the Integer Primary Key" # http://www.sqlite.org/lang_createtable.html
The data for each table in SQLite is stored as a B-Tree structure
containing an entry for each table row, using the rowid value as the
key. This means that retrieving or sorting records by rowid is fast.
Because it's stored in that order in the B-tree structure, it should be fast to order by the int primary key. Make sure it's an alias for rowid though - more in that article.
Also, if you're going to be doing queries where username = 'bob', you should consider an index on the username column - especially there's going to be many users which makes the index effective because of high selectivity. In contrast, adding an index on a column with values like 1 and 0 only leads to low selectivity and renders the index very ineffective. So, if you have 3 users :) it's not worth it.
You can remove the order_id column & index entirely (unless you need them for something other than this sorting).
SQLite tables always have a integer primary key - in this case, your username column has silently been made a unique key, so the table only has the one integer primary key. The key column is called rowid. For your sorting purpose, you'll want to explicitly make it AUTOINCREMENT so that every row always has a higher rowid than older rows.
You probably want to read http://www.sqlite.org/autoinc.html
CREATE TABLE foo (
rowid INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE KEY,
...
Then your select becomes
select * from foo order by rowed;
One advantage of this approach is that you're re-using the index SQLite will already be placing on your table. A date or order_id column is going to mean an extra index, which is just overhead here.

How to make sure SQLite never create a row with the same ID twice?

I have a SQLite table that looks like this:
CREATE TABLE Cards (id INTEGER PRIMARY KEY, name TEXT)
So each time I create a new row, SQLite is going to automatically assign it a unique ID.
However, if I delete a row and then create a new row, the new row is going to have the ID of the previously deleted row.
How can I make sure it doesn't happen? Is it possible to somehow force SQLite to always give really unique IDs, that are even different from previously deleted rows?
I can do it in code but I'd rather let SQLite do it if it's possible. Any idea?
Look at autoincrement (INTEGER PRIMARY KEY AUTOINCREMENT). It will guarantee this and if the request can't be honored it will fail with SQLITE_FULL.

Resources