I currently have a table called User which has a id column which is created as
'INTEGER PRIMARY KEY'
Lets say I have created two users so the table has id 1 and 2
If I delete the second user and create a third the id is 2, I need this to be 3
So it seems Android is selecting the next available id, how can I change this to its more like a sequence number?
Regards
Make it INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL. Here's what the docs say:
If a column has the type INTEGER PRIMARY KEY AUTOINCREMENT then... the ROWID chosen
for the new row is at least one larger than the largest ROWID that has
ever before existed in that same table.
The behavior implemented by the AUTOINCREMENT keyword is subtly
different from the default behavior. With AUTOINCREMENT, rows with
automatically selected ROWIDs are guaranteed to have ROWIDs that have
never been used before by the same table in the same database. And the
automatically generated ROWIDs are guaranteed to be monotonically
increasing.
SQLite AUTOINCREMENT is a keyword used for auto incrementing a value of a field in the table. We can auto increment a field value by using AUTOINCREMENT keyword when creating a table with specific column name to auto incrementing it.
The keyword AUTOINCREMENT can be used with INTEGER field only.
Syntax:
The basic usage of AUTOINCREMENT keyword is as follows:
CREATE TABLE table_name(
column1 INTEGER AUTOINCREMENT,
column2 datatype,
column3 datatype,
.....
columnN datatype,
);
For Example See Below:
Consider COMPANY table to be created as follows:
sqlite> CREATE TABLE TB_COMPANY_INFO(
ID INTEGER PRIMARY KEY AUTOINCREMENT,
NAME TEXT NOT NULL,
AGE INT NOT NULL,
ADDRESS CHAR(50),
SALARY REAL
);
Now, insert following records into table TB_COMPANY_INFO:
INSERT INTO TB_COMPANY_INFO (NAME,AGE,ADDRESS,SALARY)
VALUES ( 'MANOJ KUMAR', 40, 'Meerut,UP,INDIA', 200000.00 );
Now Select the record
SELECT *FROM TB_COMPANY_INFO
ID NAME AGE ADDRESS SALARY
1 Manoj Kumar 40 Meerut,UP,INDIA 200000.00
If speaking for ANDROID, yes, above answers are correct, except naming of the id column.
database.execSQL("CREATE TABLE IF NOT EXISTS "
+ TableName
+ " ( rowid INTEGER PRIMARY KEY AUTOINCREMENT, Raqam VARCHAR, ChandBor INT(3));");
It looks like in Android it should be named as 'rowid'.
And with Cursor you need to instantiate it like:
Cursor cursorLcl = database.rawQuery("SELECT *," + TableName + ".rowid AS rowid" + " FROM " +
TableName, null);
Otherwise it didnt work for me. I don't know why it so.
Just remember for android when writing tot the database (ie. executing),
do
INSERT INTO TABLE_NAME (param1name, param2name) VALUES (param1,param2)
and there is no need to add a place holder for the auto increment. It will add it by itself when adding a record. If you do not declare the params that you will put in, you will get the error x amount of variables expected and you only gave x-1, and this is because you are not supposed to give any place holding value for the auto increment column
Related
I'm trying to a have a table with an auto incremented primary key. The SQL query for table creation is included.
Problem is the auto-increment does not work. Meaning when I insert a row with NULL as the value of conversation_id it just inserts null. I have this problem on multiple tables.
-- Table: conversations
CREATE TABLE conversations (
conversation_id INTEGER (64) PRIMARY KEY
UNIQUE,
target_id BIGINT (64),
sender_id BIGINT (64),
status STRING (16) NOT NULL
DEFAULT unseen,
is_group INTEGER (1) NOT NULL
DEFAULT (0),
last_update INTEGER (32) DEFAULT (0),
target_name STRING (64),
target_photo STRING (256),
unread_count INTEGER (10) DEFAULT (0),
last_message STRING (256)
);
The following is the method I use to insert into table:
public Conversation addConversation(Conversation conversation) {
SQLiteDatabase db = getWritableDatabase();
ContentValues row = new ContentValues();
row.put("target_id", conversation.getTargetID());
row.put("sender_id", conversation.getSenderID());
row.put("target_name", conversation.getTargetName());
row.put("target_photo", conversation.getTargetPhoto());
row.put("status", conversation.getStatus());
row.put("unread_count", conversation.getUnreadCount());
row.put("last_message", conversation.getLastMessage());
conversation.setConversationID(db.insert(TBL_CONVERSATIONS, null, row));
Log.d(TAG, "conversation added: "+conversation.getConversationID());
db.close();
return conversation;
}
The curious thing here is when I retrieve the insert id from insert method it returns the correct value, but the actual database field is null.
If I understand correctly A column declared INTEGER PRIMARY KEY will autoincrement. [Cite]
From documentation:
A table created using CREATE TABLE AS has no PRIMARY KEY and no
constraints of any kind. The default value of each column is NULL.
You don't have to add UNIQUE constraint on a COLUMN that has PRIMARY KEY constraint.
Explanation:
A UNIQUE constraint is similar to a PRIMARY KEY constraint, except
that a single table may have any number of UNIQUE constraints.
Instead add NOT NULL.
This is why:
According to the SQL standard, PRIMARY KEY should always imply NOT
NULL. Unfortunately, due to a bug in some early versions, this is not
the case in SQLite. Unless the column is an INTEGER PRIMARY KEY or the
table is a WITHOUT ROWID table or the column is declared NOT NULL,
SQLite allows NULL values in a PRIMARY KEY column. SQLite could be
fixed to conform to the standard, but doing so might break legacy
applications. Hence, it has been decided to merely document the fact
that SQLite allowing NULLs in most PRIMARY KEY columns.
I recommend using this Column definition:
CREATE TABLE conversations (
conversation_id INTEGER PRIMARY KEY NOT NULL AUTOINCREMENT,
...
}
Most likely the return value you are seeing is the row's ROWID. A ROWID is a hidden column available in every table, unless explicitly removed. According to the official documentation, when you define an INTEGER PRIMARY KEY, it should automatically become an alias for the ROWID. That's also why AUTOINCREMENT is not needed when you define your column in this way.
With one exception noted below, 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. Such a column is usually referred to
as an "integer primary key". 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.
See: CREATE TABLE documentation
Either your column is not an INTEGER, or it is not a PRIMARY KEY. Taking a closer look at your create-statement I can see one or two possible culprits.
UNIQUE vs. PRIMARY KEY
A primary key is unique by default. According to the syntax definition (which you can find on the same documentation page as the citation above) you should choose either PRIMARY KEY or UNIQUE, not both.
COLUMN length restrictions
ROWID is already 64-bit by default. You have specified length 64, but lengths are not specified in bits. You may have specified a 64-byte integer here, which I'm sure was not intended. This should actually not be a problem however, since SQLite ignores length-constraints. So it is not meaningful to specify them.
TLDR
Replace this code:
conversation_id INTEGER (64) PRIMARY KEY UNIQUE
With this:
conversation_id INTEGER PRIMARY KEY AUTOINCREMENT
I just put autoincrement in the query and it works fine .
like this
id integer primary key autoincrement
It is a bit confusing.... If I implement BaseColumns for each of my tables it automatically create an autoincremented primary key for me called _ID but then Do I need to create my own primary keys for each of my tables as well or is it redundant or even not necessary?
In case I need my own primary key, let's say, _MyID, I guess the primary key will be formed by _ID and my own (_MyID), right? so in this case, it would be possible to insert the more than one register with the same _MyID.... as _ID is autoincremented automatically, that is:
_ID _MyID Other Fields.....
1 1000 ....
2 1000 ....
3 1000 ....
... and so on
so in this case, how to control that only one register can have the value 1000 for _MyID?
Also, I guess I can use _ID column to act as a foreign key with other tables, right?
The main use for BaseColumns._ID is that Android's CursorAdapter will look for that column name in the cursor you give it. There may be other classes that do the same, but I can't think of any off the top of my head. If you aren't using CursorAdapter, then there's really nothing binding you to using _id as a column name in your table and you can name the column however you like.
it automatically create an autoincremented primary key for me called _ID
There is nothing automatic about it based on what you've shown so far. You will only have such a column if you executed SQL like this:
CREATE TABLE tableName (_id INTEGER PRIMARY KEY AUTOINCREMENT, ...);
You can just as easily leave it out or give a different name to the primary key. Furthermore, there is nothing that requires your primary key to be auto-incremented; as long as the values are unique, it satisfies the primary key requirement. In other words, this is fine too:
CREATE TABLE tableName (_id INTEGER PRIMARY KEY, ...);
In case I need my own primary key, let's say, _MyID, I guess the primary key will be formed by _ID and my own (_MyID), right?
Not quite. You would have to do something like this:
CREATE TABLE tableName (_id INTEGER, _myId INTEGER, ..., PRIMARY KEY(_id, myId));
This creates a composite key, but note that neither of the two columns are themselves declared as primary key. Honestly though, if you don't need such an arrangement, then stick to one primary key.
One last thing:
If you are planning to use CursorAdapter, you might want to name the column _id for convenience, but even then you don't have to. All that matters is the cursor has a column by that name. The actual column in the table can have a different name, you just have to alias it at query time so that it has the proper name in the cursor:
SELECT _myId as _id, ... FROM ...;
According to some blogs like http://reigndesign.com/blog/using-your-own-sqlite-database-in-android-applications/ and even in some of the aswers here.
One of the first steps before including the datababe into the project is to rename the primary id field of your tables to "_id" so Android will know where to bind the id field of your tables.
What should be done with a table that have a combined primary key
Assume that i'm creating the relation between the product id and the store id to assign it's price.
CREATE TABLE `Products-Stores` (
`product` INTEGER NOT NULL,
`store` INTEGER NOT NULL,
`price` INTEGER NOT NULL,
PRIMARY KEY(product,store)
);
There is no need to rename any column in your database. SQL allows column aliases like this:
SELECT integer_primary_key AS _id
...
The only time this is necessary is when you are using a ListAdapter to display the contents of a cursor queried from your DB. You must have an integer primary key column, named "_id" in the cursor, to do that
Better yet, every SQLite database table has an implicit column named "rowid". You don't even have to have your own integer primary key column. Just use rowid, like so:
SELECT rowid AS _id
...
EDITED TO INCLUDE #CL's EXPLANATION OF WORKING JOINS
Obviously, this trick won't work, for many kinds of joins. As long as the rowids are unique over all the rows in the join, though, it works fine.
Simple problem which got me stuck for hours now...
When I add a value into my database via db.insert(TABLE_NAME, null, myValues) the new id of my item is returned.
Exactly after this call I'd like to update my entry. Therefore I call db.update(TABLE_NAME, values, MY_ID_NAME + " = " + returnedId, null). I'd expect to get 1 returned as one entry is affected by this update.
However, I get 0. My id is simply not saved into the database. If I try more complex queries I always get every value I need but the id, which is always 0.
I've no idea how to find my fault - I get a cursor, try to get the id by long id = cursor.getLong(0) and it will return 0.
My CreateStatement starts with:
"CREATE TABLE " + TABLE_NAME + "("+ MY_ID_NAME + " LONG PRIMARY KEY, "....
Also I need to mention that I work on an In-Memory Database for testing purposes.
What is missing? What am I doing wrong?
Also: I decided to open the database only at the beginning via Singleton-Pattern - this wasn't an issue until now
Edit2: What I also forgot to mention is that I'm currently working in an InstrumentationTestCase-environent for some unit-tests
I'm almost positive that the primary ID number in Android's SQLite must be called _id during table creation and referred to when querying the table as _ID.
so in this case:
"CREATE TABLE " + TABLE_NAME + "(_id LONG PRIMARY KEY, "....
Edit:
Try this:
"CREATE TABLE " + TABLE_NAME + "("+ MY_ID_NAME + " LONG PRIMARY KEY AUTOINCREMENT, "...
Although I am curious why you choose to use LONG instead of INTEGER
After hours of testing and debugging, Zolnoor's answer was nearly correct:
SQLite does not allow a LONG PRIMARY KEY statement but an INTEGER PRIMARY KEY as described in the SQLite-Documentation:
The data for rowid tables is stored as a B-Tree structure containing one entry for each table row, using the rowid value as the key. This means that retrieving or sorting records by rowid is fast. Searching for a record with a specific rowid, or for all records with rowids within a specified range is around twice as fast as a similar search made by specifying any other PRIMARY KEY or indexed value.
With one exception noted below, 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. Such a column is usually referred to as an "integer primary key". 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 a table with a composite primary key and I am having trouble inserting. The code used to create the table is:
CREATE TABLE ClassEvent (
EventName varchar(10) NOT NULL,
CourseId varchar(10) NOT NULL,
EventType varchar(20),
EventWeight number(3),
DueDate DATE NOT NULL,
FOREIGN KEY (CourseId) REFERENCES Courses(CourseId),
PRIMARY KEY (CourseId, EventName));
The problem I am having is when I want to insert records that have values that may not be unique for the columns CourseId or EventName, but are a unique combination of the 2.
for example, if I try to run the following 2 inserts:
INSERT INTO ClassEvent VALUES('Assignment 1','60-415','Assignment',10,'12/10/2010');
INSERT INTO ClassEvent VALUES('Project 1','60-415','Project',15,'5/12/2010');
I get the following error:
Error: columns CourseId, EventName are not unique.
and the second insert does not make it into the DB. Why does this error out? I thought that a composite primary key requires that the combination of both values are unique. In my above inserts, the values for the EventName column are different even though the values for CourseId are the same. Shouldn't this be seen as 2 unique combinations and thus 2 different primary keys?
My table needs to be able to hold several different events for each CourseId, but each Event must be unique for each Course. I need to be able to insert values into the table like:
EventName CourseId
Assignment 1 60-415
Project 1 60-415
Assignment2 60-415
Project 2 60-415
Assignment 1 60-367
Project 1 60-367
and so on. Can anyone tell me how I can get this to work? Why are these composite PK's not being seen as unique entries? Any help would be much appreciated.
Here is the java function I am using for the insert:
public void addNewClassEvent(ContentValues values) {
SQLiteDatabase db = openConnection();
db.insert("ClassEvent", null, values);
db.close();
}
Could this be causing the problem?
You can have a composite primary key in SQLite, but you
have to create the key when you create the table:
CREATE TABLE example1(
field1 FLOAT,
field2 TEXT,
PRIMARY KEY(field1, field2)
);
You cannot create the primary key after the fact using ALTER TABLE.
On the other hand, you can create a UNIQUE INDEX after the fact
which has essentially the same effect as a PRIMARY KEY:
CREATE UNIQUE INDEX pk_index ON "table1"("field1","field2");
I am not sure how you have created, the tables, and if you have added the primary index later, but grab the database to your desktop, and check out how works in a desktop environment.
You can't make combinations like that, but you don't need them. What is stopping you from just having a truly id column ?