Is there any difference between INT PRIMARY KEY and INTEGER PRIMARY KEY when defining a schema for a table?
When int primary key is used, I got sqlite_autoindex thing generated;
when integer primary key , I got sqlite_sequence table generated.
what's the difference? what side effects can have the first and second variants?
UPDATE: SQLite's ROWID column is now a 64-bit integer:
In SQLite, a column with type INTEGER PRIMARY KEY is an alias for the ROWID (except in WITHOUT ROWID tables) which is always a 64-bit signed integer.
It is all explained in SQLite 3 documentation:
2.0 The INTEGER PRIMARY KEY
One exception to the typelessness of SQLite is a column whose type is INTEGER PRIMARY KEY. (And you must use "INTEGER" not "INT". A column of type INT PRIMARY KEY is typeless just like any other.) INTEGER PRIMARY KEY columns must contain a 32-bit signed integer. Any attempt to insert non-integer data will result in an error.
INTEGER PRIMARY KEY columns can be used to implement the equivalent of AUTOINCREMENT. If you try to insert a NULL into an INTEGER PRIMARY KEY column, the column will actually be filled with an integer that is one greater than the largest key already in the table. Or if the largest key is 2147483647, then the column will be filled with a random integer. Either way, the INTEGER PRIMARY KEY column will be assigned a unique integer. You can retrieve this integer using the sqlite_last_insert_rowid() API function or using the last_insert_rowid() SQL function in a subsequent SELECT statement.
Yes, there is a difference: INTEGER is a special case in SQLite, when the database does not create a separate primary key, but reuses the ROWID column instead. When you use INT (or any other type that "maps" to INTEGER internally) a separate primary key is created.
That is why you see sqlite_autoindex created for the INT primary key, and no index created for the one of type INTEGER: SQLite reuses a built-in indexing structure for the integer primary key, rendering the autoindex unnecessary.
That is why the INTEGER primary key is more economical, both in terms of storage and in terms of performance.
See this link for details.
Just to add albeit implied already on the answers here. The INTEGER PRIMARY KEY column that you created is simply an alias for ROWID or _ROWID_ or OID. And if the AUTOINCREMENT keyword is added then every new record inserted is an increment of 1 of the last ROWID and the last ROWID is kept by an sqlite internal table named sqlite_sequence.
See link here and here
On the other hand if you declare a column as INT PRIMARY KEY sqlite create an automatic index (hence the sqlite_autoindex) to keep track of the value inserted in the primary key to make sure it is unique.
Related
I'm currently debating between two strategies to using a text column as a key.
The first one is to simply use the text column itself as a key, as such:
create table a(
key_a text primary key,
)
create table b(
key_b text primary key,
)
create table c(
key_a text,
key_b text,
foreign key("key_a") references a("key_a"),
foreign key("key_b") references b("key_b")
)
I'm concerned that this would result in every key being duplicated, once in a and b and another in c, since text isn't stored inline.
My second approach is to use an autoincrement id on the first two tables as a primary key, and use those ids on table c to refer to them, as such:
create table a(
id_a integer,
key_a text unique,
primary key("id_a" autoincrement)
)
create table b(
id_b integer,
key_b text unique,
primary key("id_a" autoincrement)
)
create table c(
id_a integer,
id_b integer,
foreign key("id_a") references a("id_a"),
foreign key("id_b") references b("id_b")
)
Am I right to be concerned about text duplication in the first case? Or does sqlite somehow intern these and just use an id for both, akin to what the second strategy does?
SQLite does not automatically compress text. So the answer to your question is "no".
Should you use text or an auto-incrementing id as the primary key? This can be a complex question. But happily, the answer is that it doesn't make much difference. That said, there are some considerations:
Integers are of fixed length. In general, fix length keys are slightly more efficient in B-tree indexes than variable length keys.
If the strings are short (like 1 or 2 or 3 characters), then they may be shorter -- or no longer -- than integers.
If you change the string (say, if it is originally misspelled), then using an "artificial" primary key makes this easy: just change the value in one table. Using the string itself as a key can result in lots of updates to lots of tables.
Am I right to be concerned about text duplication in the first case?
Or does sqlite somehow intern these and just use an id for both, akin
to what the second strategy does?
Yes, you are right to be concerned. The text will be duplicated.
Also, even if you did not define an integer primary key in your 1st approach, there is one.
From Rowid Tables:
The PRIMARY KEY of a rowid table (if there is one) is usually not the
true primary key for the table, in the sense that it is not the unique
key used by the underlying B-tree storage engine. The exception to
this rule is when the rowid table declares an INTEGER PRIMARY KEY. In
the exception, the INTEGER PRIMARY KEY becomes an alias for the rowid.
The true primary key for a rowid table (the value that is used as the
key to look up rows in the underlying B-tree storage engine) is the
rowid.
In your 2nd approach actually you are not creating a new column in each of the tables a and b by defining an integer primary key.
What you are doing is aliasing the existing rowid column:
id_a becomes the alias of rowid of the table a
id_b becomes the alias of rowid of the table b.
So, defining these integer primary keys is not more expensive in terms of space in the parent tables.
Although with your 1st approach you can avoid explicit updates in the child tables when you update a value in the parent tables by defining the foreign keys with ON UPDATE CASCADE, your 2nd approach is what I would suggest.
An integer primary key with a value assigned to it by the system and you don't even have to know or worry about it is common practice.
All you have to do is use that primary key and its corresponding foreign keys in the queries that you create to access the parent tables when you want to fetch from them the text values.
For performance (also it is a good db practice) you should stick to numeric/int value for the Primary Key.
As for the second approach, I'm not getting the concept you are after. Could you elaborate more on this?
I have a composite primary key {shop_id, product_id} for SQLite
Now, I want an auto-increment value for product_id which resets to 1 if shop id is changed. Basically, I want auto-generated composite key
e.g.
Shop ID Product Id
1 1
1 2
1 3
2 1
2 2
3 1
Can I achieve this with auto-increment? How?
Normal Sqlite tables are B*-trees that use a 64-bit integer as their key. This is called the rowid. When inserting a row, if a value is not explicitly given for this, one is generated. An INTEGER PRIMARY KEY column acts as an alias for this rowid. The AUTOINCREMENT keyword, which can only be used on said INTEGER PRIMARY KEY column, contrary to the name, merely alters how said rowid is calculated - if you leave out a value, one will be created whether that keyword is present or not, because it's really the rowid and must have a number. Details here. (rowid values are generally generated in increasing, but not necessarily sequential, order, and shouldn't be treated like a row number or anything like that, btw).
Any primary key other than a single INTEGER column is treated as a unique index, while the rowid remains the true primary key (Unless it's a WITHOUT ROWID table), and is not autogenerated. So, no, you can't (easily) do what you want.
I would probably work out a database design where you have a table of shops, a table of products, each with their own ids, and a junction table that establishes a many-to-many relation between the two. This keeps the product id the same between stores, which is probably going to be less confusing to people - I wouldn't expect the same item to have a different SKU in two different stores of the same chain, for instance.
Something like:
CREATE TABLE stores(store_id INTEGER PRIMARY KEY
, address TEXT
-- etc
);
CREATE TABLE product(prod_id INTEGER PRIMARY KEY
, name TEXT
-- etc
);
CREATE TABLE inventory(store_id INTEGER REFERENCES stores(store_id)
, prod_id INTEGER REFERENCES product(prod_id)
, PRIMARY KEY(store_id, prod_id)) WITHOUT ROWID;
I've a table TABLE1 with my data. Another clean table TABLE2 as follow:
"TABLE2"(ipt TEXT,instant NUM, id integer auto_increment);
I want to select IP and instant in TABLE1 and insert it into TABLE2 but I don't know why the auto_increment doesn't work.
If someone has an idea.
AUTOINCREMENT can only be used in one situation. and that is for a column defined with a type/constraint of INTEGER PRIMARY KEY.
auto_increment is not a valid keyword and if you used column id integer auto_increment the result would be a column named id with a type of integer auto_increment which would then effectively be a column type of INTEGER i.e. the column's type affinity would be INTEGER. Datatypes In SQLite Version 3
i.e. you must have exactly column_name INTEGER PRIMARY KEY AUTOINCREMENT. (case is irrelevant)
It can also only be coded once per table.
INTEGER PRIMARY KEY with or without AUTOINCREMENT is a special case where the named column is made to be an alias of the rowid column. The rowid being a column that uniquely identifies the row, which is generally hidden (for want of a better description). rowid will not exists if the table is created with the WITHOUT ROWID keyword(s). In which case AUTOINCREMENT cannot be coded within a column definition.Clustered Indexes and the WITHOUT ROWID Optimization
Saying that it is almost certain that you do not in fact need to code AUTOINCREMENT just coding column_name INTEGER PRIMARY KEY will very likely be sufficient and better for your needs. The column will still be given a unique identifier. an integer (64 bit signed) 1 for the first row inserted then likely 2, 3, 4 .....
- Note there is no guarantee that numbering will be sequential/monotonically increased.
Adding AUTOINCREMENT only ensures that the unique identifier is greater and in doing so imposes a limit that the identifier when reaching the highest possible value will subsequently result in an SQLITE_FULL exception, whilst without unused/free values (e.g. deleted rows) that are lower than the highest could be utilised.
To quote the SQLite documentation :-
The AUTOINCREMENT keyword imposes extra CPU, memory, disk space, and
disk I/O overhead and should be avoided if not strictly needed. It is
usually not needed.
SQLite Autoincrement
I want to insert an element in my table :
events(eventID int primary key autoincrement,type text,date date,coordinates text,deviceID int,userID int)
how the auto increment works?
in fact when I did not write the id I have an error like "you have 6 columns but 5 were supplied."
and if I just write nil I have always id=0, this is what I wrote :
insert into events(type,date,coordinates,deviceId,userID) values('%#','%#','%#','%d','%d');
thanks by advance
The documentation says that
if a rowid table has a primary key that consists of a single column and the declared type of that column is "INTEGER" in any mixture of upper and lower case, then the column becomes an alias for the rowid. […] A PRIMARY KEY column only becomes an integer primary key if the declared type name is exactly "INTEGER". Other integer type names like "INT" or "BIGINT" or "SHORT INTEGER" or "UNSIGNED INTEGER" causes the primary key column to behave as an ordinary table column with integer affinity and a unique index, not as an alias for the rowid.
I have the following SQLite query:
CREATE TABLE Logs ( Id integer IDENTITY (1, 1) not null CONSTRAINT PKLogId PRIMARY KEY, ...
IDENTITY (1, 1) -> What does this mean?
PKLogId what is this? This doesn't seem to be defined anywhere
I want Id to be integer primary key with autoincrement. I would like to be able to insert into this Logs table omitting Id column in my query. I want Id to be automatically added and incremented. Is this possible? How can I do this?
At the moment when I try to insert without Id I get:
Error while executing query: Logs.Id may not be NULL
I'm not sure whether you're actually using SQLite according to the syntax of your example.
If you are, you may be interested in SQLite FAQ #1: How do I create an AUTOINCREMENT field?:
Short answer: A column declared INTEGER PRIMARY KEY will
autoincrement.
Change it to:
CREATE TABLE Logs ( Id integer PRIMARY KEY,....
If you are, you may be interested in SQLite FAQ #1: How do I create an AUTOINCREMENT field?:
Short answer: A column declared INTEGER PRIMARY KEY will auto increment.
This in fact is not entirely accurate. An integer primary key will indeed increment, however if the table drops all rows, it starts from the beginning again, It is important if you want to have all associated records tied correctly to use the autoincrement description after the primary key declaration on the integer field.