Related
I realize there are many answers here for SQLite versioning, but I couldn't find an answer for my specific issue. I was doing fine with Version 1 for quite a while. I then needed to add another column "TAG" to my table and implemented the following code in onUpgrade.
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DATABASE_CREATE);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < 2) db.execSQL(DATABASE_ALTER_TAG);
}
It worked great. No issues. The TAG column was working as expected reading and writing -- until I reinstalled after a full uninstall. The DB now won't work using code that worked before the uninstall / reinstall.
I suspect it is because after uninstall / reinstall the "old version" is null (which is not < 2) and the TAG column is not being added. I'm not entirely sure although. Is my onUpgrade code the problem?
I suppose I could rewrite my my database as Version 1 with the TAG column, but I'd like to know what is wrong with my code for future reference.
EDIT QUESTION
OK, thanks for the responses so far. I understand how to get the DB to work for someone who is installing the app fresh. I also understand how to get the DB to work for someone who is going from Version 1 to Version 2. I don't yet understand how to get it to work for both users (fresh install vs. someone who is just upgrading).
Your assumption is definitely not correct. Primitive data types are not object and hence are not null.
Just make sure your create statement i.e. db.execSQL(DATABASE_CREATE); reflects the new database table structure and not the old one i.e. with the new TAG column.
I have created my tables in my SQLiteOpenHelper onCreate() but receive
SQLiteException: no such table
or
SQLiteException: no such column
errors. Why?
NOTE:
(This is the amalgamated summary of tens of similar questions every week. Attempting to provide a "canonical" community wiki question/answer here so that all those questions can be directed to a good reference.)
SQLiteOpenHelper onCreate() and onUpgrade() callbacks are invoked when the database is actually opened, for example by a call to getWritableDatabase(). The database is not opened when the database helper object itself is created.
SQLiteOpenHelper versions the database files. The version number is the int argument passed to the constructor. In the database file, the version number is stored in PRAGMA user_version.
onCreate() is only run when the database file did not exist and was just created. If onCreate() returns successfully (doesn't throw an exception), the database is assumed to be created with the requested version number. As an implication, you should not catch SQLExceptions in onCreate() yourself.
onUpgrade() is only called when the database file exists but the stored version number is lower than requested in the constructor. The onUpgrade() should update the table schema to the requested version.
When changing the table schema in code (onCreate()), you should make sure the database is updated. Two main approaches:
Delete the old database file so that onCreate() is run again. This is often preferred at development time where you have control over the installed versions and data loss is not an issue. Some ways to delete the database file:
Uninstall the application. Use the application manager or adb uninstall your.package.name from the shell.
Clear application data. Use the application manager.
Increment the database version so that onUpgrade() is invoked. This is slightly more complicated as more code is needed.
For development time schema upgrades where data loss is not an issue, you can just use execSQL("DROP TABLE IF EXISTS <tablename>") in to remove your existing tables and call onCreate() to recreate the database.
For released versions, you should implement data migration in onUpgrade() so your users don't lose their data.
To further add missing points here, as per the request by Jaskey
Database version is stored within the SQLite database file.
catch is the constructor
SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)
So when the database helper constructor is called with a name (2nd param), platform checks if the database exists or not and if the database exists, it gets the version information from the database file header and triggers the right call back
As already explained in the older answer, if the database with the name doesn't exists, it triggers onCreate.
Below explanation explains onUpgrade case with an example.
Say, your first version of application had the DatabaseHelper (extending SQLiteOpenHelper) with constructor passing version as 1 and then you provided an upgraded application with the new source code having version passed as 2, then automatically when the DatabaseHelper is constructed, platform triggers onUpgrade by seeing the file already exists, but the version is lower than the current version which you have passed.
Now say you are planing to give a third version of application with db version as 3 (db version is increased only when database schema is to be modified). In such incremental upgrades, you have to write the upgrade logic from each version incrementally for a better maintainable code
Example pseudo code below:
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch(oldVersion) {
case 1:
//upgrade logic from version 1 to 2
case 2:
//upgrade logic from version 2 to 3
case 3:
//upgrade logic from version 3 to 4
break;
default:
throw new IllegalStateException(
"onUpgrade() with unknown oldVersion " + oldVersion);
}
}
Notice the missing break statement in case 1 and 2. This is what I mean by incremental upgrade.
Say if the old version is 2 and new version is 4, then the logic will upgrade the database from 2 to 3 and then to 4
If old version is 3 and new version is 4, it will just run the upgrade logic for 3 to 4
onCreate()
When we create DataBase at a first time (i.e Database is not exists) onCreate() create database with version which is passed in
SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)
onCreate() method is creating the tables you’ve defined and executing any other code you’ve written. However, this method will only be called if the SQLite file is missing in your app’s data directory (/data/data/your.apps.classpath/databases).
This method will not be called if you’ve changed your code and relaunched in the emulator. If you want onCreate() to run you need to use adb to delete the SQLite database file.
onUpgrade()
SQLiteOpenHelper should call the super constructor.
The onUpgrade() method will only be called when the version integer is larger than the current version running in the app.
If you want the onUpgrade() method to be called, you need to increment the version number in your code.
May be I am too late but I would like to share my short and sweet answer.
Please check Answer for a same problem. It will definitely help you. No more deep specifications.
If you are confident about syntax for creating table, than it may happen when you add new column in your same table, for that...
1) Uninstall from your device and run it again.
OR
2) Setting -> app -> ClearData
OR
3) Change DATABASE_VERSION in your "DatabaseHandler" class (If you have added new column than it will upgrade automatically)
public DatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
OR
4) Change DATABASE_NAME in your "DatabaseHandler" class (I faced same problem. But I succeed by changing DATABASE_NAME.)
Points to remember when extending SQLiteOpenHelper
super(context, DBName, null, DBversion); - This should be invoked first line of constructor
override onCreate and onUpgrade (if needed)
onCreate will be invoked only when getWritableDatabase() or getReadableDatabase() is executed. And this will only invoked once when a DBName specified in the first step is not available. You can add create table query on onCreate method
Whenever you want to add new table just change DBversion and do the queries in onUpgrade table or simply uninstall then install the app.
You can create database & table like
public class DbHelper extends SQLiteOpenHelper {
private static final String DBNAME = "testdatbase.db";
private static final int VERSION = 1;
public DbHelper(Context context) {
super(context, DBNAME, null, VERSION);
// TODO Auto-generated constructor stub
}
#Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
db.execSQL("create table BookDb(id integer primary key autoincrement,BookName text,Author text,IssuedOn text,DueDate text,Fine text,Totalfine text");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS BookDb");
onCreate(db);
}
}
Note : if you want create another table or add columns or no such table, just increment the VERSION
onCreate is called for the first time when creation of tables are needed. We need to override this method where we write the script for table creation which is executed by SQLiteDatabase. execSQL method. After executing in first time deployment, this method will not be called onwards.
onUpgrade
This method is called when database version is upgraded. Suppose for the first time deployment , database version was 1 and in second deployment there was change in database structure like adding extra column in table. Suppose database version is 2 now.
Sqlite database override two methods
1) onCreate():
This method invoked only once when the application is start at first time . So it called only once
2)onUpgrade()
This method called when we change the database version,then this methods gets invoked.It is used for the alter the table structure like adding new column after creating DB Schema
Uninstall your application from the emulator or device. Run the app again. (OnCreate() is not executed when the database already exists)
no such table found is mainly when you have not opened the SQLiteOpenHelper class with getwritabledata() and before this you also have to call make constructor with databasename & version.
And OnUpgrade is called whenever there is upgrade value in version number given in SQLiteOpenHelper class.
Below is the code snippet (No such column found may be because of spell in column name):
public class database_db {
entry_data endb;
String file_name="Record.db";
SQLiteDatabase sq;
public database_db(Context c)
{
endb=new entry_data(c, file_name, null, 8);
}
public database_db open()
{
sq=endb.getWritableDatabase();
return this;
}
public Cursor getdata(String table)
{
return sq.query(table, null, null, null, null, null, null);
}
public long insert_data(String table,ContentValues value)
{
return sq.insert(table, null, value);
}
public void close()
{
sq.close();
}
public void delete(String table)
{
sq.delete(table,null,null);
}
}
class entry_data extends SQLiteOpenHelper
{
public entry_data(Context context, String name, SQLiteDatabase.CursorFactory factory,
int version) {
super(context, name, factory, version);
// TODO Auto-generated constructor stub
}
#Override
public void onCreate(SQLiteDatabase sqdb) {
// TODO Auto-generated method stub
sqdb.execSQL("CREATE TABLE IF NOT EXISTS 'YOUR_TABLE_NAME'(Column_1 text not null,Column_2 text not null);");
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
onCreate(db);
}
}
If you forget to provide a "name" string as the second argument to the constructor, it creates an "in-memory" database which gets erased when you close the app.
Your database name must end with .db also your query strings must have a terminator (;)
Recheck your query in ur DatabaseHandler/DatabaseManager class(which ever you have took)
In my case I get items from XML-file with <string-array>, where I store <item>s. In these <item>s I hold SQL strings and apply one-by-one with databaseBuilder.addMigrations(migration). I made one mistake, forgot to add \ before quote and got the exception:
android.database.sqlite.SQLiteException: no such column: some_value (code 1 SQLITE_ERROR): , while compiling: INSERT INTO table_name(id, name) VALUES(1, some_value)
So, this is a right variant:
<item>
INSERT INTO table_name(id, name) VALUES(1, \"some_value\")
</item>
Sqliteopenhelper's method have methods create and upgrade,create is used when any table is first time created and upgrade method will called everytime whenever table's number of column is changed.
I'm using SQLiteDatabase in my app. My SQLiteOpenHelper.onUpgrade(..) method looks like this:
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//Save current data
ArrayList<Course> tempCourses = getAllCourses();
//Drop tables
db.execSQL("DROP TABLE IF EXISTS " + TABLE_COURSES);
db.execSQL("DROP TABLE IF EXISTS " + TABLE_ASSIGNMENTS);
//create new tables
onCreate(db);
//Add temp data back to the database
for (Course course : tempCourses) {
addCourse(course);
}
}
I want to keep the old userdata when upgrading the database schema.
However I get the following error when i increase the database version and start my app:
...
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.tak3r07.unihelper/com.tak3r07.CourseStatistics.MainActivity}: java.lang.IllegalStateException: getDatabase called recursively
...
This is because getAllCourses() will open the database again to get the data which calls the onUpgrade method (obvious loop).
But how should i store my userdata then?
Regards,
Tak3r07
The ALTER TABLE command can be used to perform some schema changes on existing tables without losing data. If you do find that you need to create the table from scratch, you should follow the following pattern:
Begin transaction
Create the new table
Do a insert .. select statement
Drop the old tables
Commit transaction
If any of the steps fail, you still have the data, and you can pick up at any step to finish the upgrade if it fails for any reason. You do not want to load all the courses into your app's memory like you're doing and then drop the tables because if your app fails to insert the courses back into the db, you'll lose all your data. Do it all in SQL.
I have created my tables in my SQLiteOpenHelper onCreate() but receive
SQLiteException: no such table
or
SQLiteException: no such column
errors. Why?
NOTE:
(This is the amalgamated summary of tens of similar questions every week. Attempting to provide a "canonical" community wiki question/answer here so that all those questions can be directed to a good reference.)
SQLiteOpenHelper onCreate() and onUpgrade() callbacks are invoked when the database is actually opened, for example by a call to getWritableDatabase(). The database is not opened when the database helper object itself is created.
SQLiteOpenHelper versions the database files. The version number is the int argument passed to the constructor. In the database file, the version number is stored in PRAGMA user_version.
onCreate() is only run when the database file did not exist and was just created. If onCreate() returns successfully (doesn't throw an exception), the database is assumed to be created with the requested version number. As an implication, you should not catch SQLExceptions in onCreate() yourself.
onUpgrade() is only called when the database file exists but the stored version number is lower than requested in the constructor. The onUpgrade() should update the table schema to the requested version.
When changing the table schema in code (onCreate()), you should make sure the database is updated. Two main approaches:
Delete the old database file so that onCreate() is run again. This is often preferred at development time where you have control over the installed versions and data loss is not an issue. Some ways to delete the database file:
Uninstall the application. Use the application manager or adb uninstall your.package.name from the shell.
Clear application data. Use the application manager.
Increment the database version so that onUpgrade() is invoked. This is slightly more complicated as more code is needed.
For development time schema upgrades where data loss is not an issue, you can just use execSQL("DROP TABLE IF EXISTS <tablename>") in to remove your existing tables and call onCreate() to recreate the database.
For released versions, you should implement data migration in onUpgrade() so your users don't lose their data.
To further add missing points here, as per the request by Jaskey
Database version is stored within the SQLite database file.
catch is the constructor
SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)
So when the database helper constructor is called with a name (2nd param), platform checks if the database exists or not and if the database exists, it gets the version information from the database file header and triggers the right call back
As already explained in the older answer, if the database with the name doesn't exists, it triggers onCreate.
Below explanation explains onUpgrade case with an example.
Say, your first version of application had the DatabaseHelper (extending SQLiteOpenHelper) with constructor passing version as 1 and then you provided an upgraded application with the new source code having version passed as 2, then automatically when the DatabaseHelper is constructed, platform triggers onUpgrade by seeing the file already exists, but the version is lower than the current version which you have passed.
Now say you are planing to give a third version of application with db version as 3 (db version is increased only when database schema is to be modified). In such incremental upgrades, you have to write the upgrade logic from each version incrementally for a better maintainable code
Example pseudo code below:
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch(oldVersion) {
case 1:
//upgrade logic from version 1 to 2
case 2:
//upgrade logic from version 2 to 3
case 3:
//upgrade logic from version 3 to 4
break;
default:
throw new IllegalStateException(
"onUpgrade() with unknown oldVersion " + oldVersion);
}
}
Notice the missing break statement in case 1 and 2. This is what I mean by incremental upgrade.
Say if the old version is 2 and new version is 4, then the logic will upgrade the database from 2 to 3 and then to 4
If old version is 3 and new version is 4, it will just run the upgrade logic for 3 to 4
onCreate()
When we create DataBase at a first time (i.e Database is not exists) onCreate() create database with version which is passed in
SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)
onCreate() method is creating the tables you’ve defined and executing any other code you’ve written. However, this method will only be called if the SQLite file is missing in your app’s data directory (/data/data/your.apps.classpath/databases).
This method will not be called if you’ve changed your code and relaunched in the emulator. If you want onCreate() to run you need to use adb to delete the SQLite database file.
onUpgrade()
SQLiteOpenHelper should call the super constructor.
The onUpgrade() method will only be called when the version integer is larger than the current version running in the app.
If you want the onUpgrade() method to be called, you need to increment the version number in your code.
May be I am too late but I would like to share my short and sweet answer.
Please check Answer for a same problem. It will definitely help you. No more deep specifications.
If you are confident about syntax for creating table, than it may happen when you add new column in your same table, for that...
1) Uninstall from your device and run it again.
OR
2) Setting -> app -> ClearData
OR
3) Change DATABASE_VERSION in your "DatabaseHandler" class (If you have added new column than it will upgrade automatically)
public DatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
OR
4) Change DATABASE_NAME in your "DatabaseHandler" class (I faced same problem. But I succeed by changing DATABASE_NAME.)
Points to remember when extending SQLiteOpenHelper
super(context, DBName, null, DBversion); - This should be invoked first line of constructor
override onCreate and onUpgrade (if needed)
onCreate will be invoked only when getWritableDatabase() or getReadableDatabase() is executed. And this will only invoked once when a DBName specified in the first step is not available. You can add create table query on onCreate method
Whenever you want to add new table just change DBversion and do the queries in onUpgrade table or simply uninstall then install the app.
You can create database & table like
public class DbHelper extends SQLiteOpenHelper {
private static final String DBNAME = "testdatbase.db";
private static final int VERSION = 1;
public DbHelper(Context context) {
super(context, DBNAME, null, VERSION);
// TODO Auto-generated constructor stub
}
#Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
db.execSQL("create table BookDb(id integer primary key autoincrement,BookName text,Author text,IssuedOn text,DueDate text,Fine text,Totalfine text");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS BookDb");
onCreate(db);
}
}
Note : if you want create another table or add columns or no such table, just increment the VERSION
onCreate is called for the first time when creation of tables are needed. We need to override this method where we write the script for table creation which is executed by SQLiteDatabase. execSQL method. After executing in first time deployment, this method will not be called onwards.
onUpgrade
This method is called when database version is upgraded. Suppose for the first time deployment , database version was 1 and in second deployment there was change in database structure like adding extra column in table. Suppose database version is 2 now.
Sqlite database override two methods
1) onCreate():
This method invoked only once when the application is start at first time . So it called only once
2)onUpgrade()
This method called when we change the database version,then this methods gets invoked.It is used for the alter the table structure like adding new column after creating DB Schema
Uninstall your application from the emulator or device. Run the app again. (OnCreate() is not executed when the database already exists)
no such table found is mainly when you have not opened the SQLiteOpenHelper class with getwritabledata() and before this you also have to call make constructor with databasename & version.
And OnUpgrade is called whenever there is upgrade value in version number given in SQLiteOpenHelper class.
Below is the code snippet (No such column found may be because of spell in column name):
public class database_db {
entry_data endb;
String file_name="Record.db";
SQLiteDatabase sq;
public database_db(Context c)
{
endb=new entry_data(c, file_name, null, 8);
}
public database_db open()
{
sq=endb.getWritableDatabase();
return this;
}
public Cursor getdata(String table)
{
return sq.query(table, null, null, null, null, null, null);
}
public long insert_data(String table,ContentValues value)
{
return sq.insert(table, null, value);
}
public void close()
{
sq.close();
}
public void delete(String table)
{
sq.delete(table,null,null);
}
}
class entry_data extends SQLiteOpenHelper
{
public entry_data(Context context, String name, SQLiteDatabase.CursorFactory factory,
int version) {
super(context, name, factory, version);
// TODO Auto-generated constructor stub
}
#Override
public void onCreate(SQLiteDatabase sqdb) {
// TODO Auto-generated method stub
sqdb.execSQL("CREATE TABLE IF NOT EXISTS 'YOUR_TABLE_NAME'(Column_1 text not null,Column_2 text not null);");
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
onCreate(db);
}
}
If you forget to provide a "name" string as the second argument to the constructor, it creates an "in-memory" database which gets erased when you close the app.
Your database name must end with .db also your query strings must have a terminator (;)
Recheck your query in ur DatabaseHandler/DatabaseManager class(which ever you have took)
In my case I get items from XML-file with <string-array>, where I store <item>s. In these <item>s I hold SQL strings and apply one-by-one with databaseBuilder.addMigrations(migration). I made one mistake, forgot to add \ before quote and got the exception:
android.database.sqlite.SQLiteException: no such column: some_value (code 1 SQLITE_ERROR): , while compiling: INSERT INTO table_name(id, name) VALUES(1, some_value)
So, this is a right variant:
<item>
INSERT INTO table_name(id, name) VALUES(1, \"some_value\")
</item>
Sqliteopenhelper's method have methods create and upgrade,create is used when any table is first time created and upgrade method will called everytime whenever table's number of column is changed.
I've watched countless tutorials and examples about SQLite on Android but I just don't get some things. could someone please explain some things to me?
This the code that I came up with until now (SQLite helper):
public class SQLiteHelper extends SQLiteOpenHelper {
public static String DATABASE_NAME = "urnik";
public static int DATABASE_VERSION = 1;
public SQLiteHelper(Context context, String name, CursorFactory factory,
int version) {
super(context, DATABASE_NAME, factory, DATABASE_VERSION);
}
//Tabela prva ura
public static String IME_TABELE = "prva_ura";
public static String ID_PREDMETA = "id_predmeta";
public static String NAZIV_PREDMETA = "naziv_predmeta";
String prva_query =
"CREATE TABLE " + IME_TABELE + " ("
+ ID_PREDMETA + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ NAZIV_PREDMETA + " TEXT" + ");";
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(prva_query);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
onCreate(db);
}
So as far as I know, this should create a new database and one table called "prva_ura". But I have a lot of questions about this.
I only created this class, I haven't attached it to MainActivity or anything, will the database still be created when app is ran for the first time or do I have to do something else?
I'm assuming the database is created when the app is launched for the first time after creating database. Can I find the database file anywhere to check if everything is as it's supposed to be?
I'd appreciate some tips in general, thank you!
The database is first created when either getReadableDatabase() or getWriteableDatabase() are called. These methods will create the db if it doesn't exist or open an existing one.
So for you to create it, just query it. Write some CRUD methods and the first one that is called will create your db.
To upgrade your database, simply increment the database version and it will auto update.
From dev page getWriteableDatabase()
http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#getReadableDatabase()
Create and/or open a database that will be used for reading and
writing. The first time this is called, the database will be opened
and onCreate(SQLiteDatabase), onUpgrade(SQLiteDatabase, int, int)
and/or onOpen(SQLiteDatabase) will be called.
Once opened successfully, the database is cached, so you can call this
method every time you need to write to the database. (Make sure to
call close() when you no longer need the database.) Errors such as bad
permissions or a full disk may cause this method to fail, but future
attempts may succeed if the problem is fixed.
All you have to do is create an instance of your class, and the database plus all tables get created.
Once the database is created, then next time your app runs, the onCreate() doesn't get called again.
As for checking that everything has been created properly, you can use the sqlite command line client
http://www.sqlite.org/sqlite.html
Details of the database location on your device are here Location of sqlite database on the device
Yes and yes.
I would advise you to look into motodev as this give you a nice database view in eclipse which is much easier to work with. It also handles generating ContentProviders for you so you do not have to write code as you have done above, simply define your database using the database view and generate the ContentProviders.
Saved me a lot of hours.
You need to call the onCreate method first probably in your main activity or any other activity to create your activity when yor app runs.
Change your onUpgrade code to this
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS prva_ura");
onCreate(db);
}
Yes there is a place where you can find your database if you switch from java to DDMS