I'm adding a table to my app's SQLite DB. All my syntax there is fine, not the issue. But I'm having some trouble getting the new table to be created properly. I added the new table....
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DATABASE_CREATE);
db.execSQL(CREATE_REQUESTS);
db.execSQL(CREATE_OVERRIDE);
}
My on create method. I have 3 tables. When I updated the version number, I got an error saying "table requests (referring to CREATE_REQUESTS) has already been created." A look at my onUpgrade method...
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS contacts");
onCreate(db);
}
Led me to understand that the line db.execSQL("DROP TABLE IF EXISTS contacts"), which refers to my DATABASE_CREATE table in the onCreate method, is used to drop the old table, then the next line, onCreate(db); recreates it. I did not add requests into that execSQL line, which is what caused the error. Here is the issue: I would rather not lose the data in the two tables I already have. Is there a way to add a table like I am trying to do, and not lose all the old data? Thanks.
You can do anything you want in onUpgrade. You can use ALTER to add new columns to your table.
Worst case, if your schema is completely and entirely different, you'll have to create the new table, populate it using data from the old table, and then delete the old table.
In any case, onUpgrade was designed to allow for a smooth upgrade without any loss of data. It's just up to you to implement it properly.
if DB version : 6
Ex : There is a table with 5 columns
When you upgrade to : 7 ( I am adding 1 new column in the 3 tables)
1. We need to add the columns when creating a table
2. onUpgrade method:
if (oldVersion < 7)
{
db.execSQL(DATABASE_ALTER_ADD_PAPER_PAID);
db.execSQL(DATABASE_ALTER_LAST_UPLOADED);
db.execSQL(DATABASE_ALTER_PAPER_LABEL);
}
Where : "DATABASE_ALTER_ADD_PAPER_PAID" is query.
EX: public static final String DATABASE_ALTER_ADD_PAPER_PAID = "ALTER TABLE "
+ TableConstants.MY_PAPERS_TABLE + " ADD COLUMN " + COLUMN_PAPER_PAID + " TEXT;";
After above two operation it will works fine for the fresh install user and app upgrade user
Related
I have five tables in my sqlite db, the five tables are created in oncreate method if I make changes to one table in upgrade method based on the previous db version when I launched the app the changes are made I can see through my logcat but it calls oncreate method and say the 4 tables already exist. How can I handle this error?
public void onUpgrade(SQLiteDatabase database, int version_old, int current_version) {
if (version_old < 3) {
database.execSQL(queryFive);
}
on onCreate I have statements that creates table initially which is then called again after onUpgrade and triggering the error they already exist. How can I handle this? Thanks.
If you make changes in one table, you should increment the DATABASE_VERSION = 1,2,3 and so on.
Whenever changes are done in database, you should first drop (delete) all table and create them again.
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME); // drop table(s),if you have five tables , drop all five
onCreate(db); // this will create all tables again
}
Update : in case of not loosing old data of other tables
You need an abstract class that implements the upgrade process described here. Then you extend this abstract class for each of your tables. In your abstract class you must store you tables in a way(list, hardcoded) so when the onUpgrade fires you iterate over the table items and for each table item you do the described steps. They will be self upgraded, keeping all their existing details. Please note that the onUpgrade event fires only once per database, that's why you need to iterate over all your tables to do the upgrade of all of them. You maintain only 1 version number over all the database.
beginTransaction
run a table creation with if not exists (we are doing an upgrade, so the table might not exists yet, it will fail alter and drop)
put in a list the existing columns List<String> columns = DBUtils.GetColumns(db, TableName);
backup table (ALTER table " + TableName + " RENAME TO 'temp_" + TableName)
create new table (the newest table creation schema)
get the intersection with the new columns, this time columns taken from the upgraded table (columns.retainAll(DBUtils.GetColumns(db, TableName));)
restore data (String cols = StringUtils.join(columns, ",");
db.execSQL(String.format(
"INSERT INTO %s (%s) SELECT %s from temp_%s",
TableName, cols, cols, TableName));
)
remove backup table (DROP table 'temp_" + TableName)
setTransactionSuccessful
other than that, there is not way you can achieve this. unless, you can create separate db file for each table.
Whenever I try to run my project second time (doesnt matter if I change anything or not), I end up getting a crash. If I change the db name or version, the application starts working again.
As far as I have understood (I am new to Android Development), that after you do getWritableDatabase() the database is actually created. After that, if the database is created for the first time, the onCreate method is called in the helper class, otherwise onUpgrade is called (please correct me on the last phrase). Now my OnCreate and OnUpgrade are fairly simple:
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE_TOI);
db.execSQL(CREATE_TABLE_HINDU);
db.execSQL(CREATE_TABLE_NEWSPAPER);
db.execSQL(CREATE_TABLE_CATEGORY);
db.execSQL(CREATE_TABLE_NEWSPAPER_CATEGORY);
Log.d(TAG, "in onCreate MySQLhelper");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all data");
db.execSQL("DROP TABLE IF EXISTS " + TABLE_TOI);
db.execSQL("DROP TABLE IF EXISTS " + TABLE_HINDU);
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NEWSPAPER);
db.execSQL("DROP TABLE IF EXISTS " + TABLE_CATEGORY);
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NEWSPAPER_CATEGORY);
onCreate(db);
}
After the getWritableDatabase command in my DAO class, I call a class Tables where I use SQLiteStatement to preload the tables. This is where the app crashes. From the logcat, the error being "Caused by: android.database.sqlite.SQLiteConstraintException: PRIMARY KEY must be unique (code 19)".
I dont remember where but I read somewher on StackOverflow regarding a problem (I dont remember the problem either), the answer was to change the database name and try, and it had worked for OP. I tried the same and it worked for me.
So now, I have to change the database name or number for every run.
My Files:
Logcat
Tables.java
MySQLiteHelper.java
Every time you create an instance of Tables, you are inserting data into the database. This does not make much sense in general -- probably you want to move that logic into onCreate() of you MySQLiteHelper class.
If for some reason you really do want to insert data every time you create an instance of Tables, you need to use unique values for your PRIMARY KEY columns. Your current code tries to insert 1, 2, 3, and 4 each time for your four rows. That will work the first time, but the second time, those rows are already there, and so you get the unique-constraint violation.
When my application starts for the first time it needs to create the database it'll be using. I don't know at what point I should be creating the database if it doesn't already exist yet, and I don't know how to ensure I don't try to create the database if it already does exist. Currently, the following works, where I execute CreateTable when the first activity in my app runs:
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
base.SetContentView(Resource.Layout.SiteListLayout);
DataManager.CreateTable<Site>();
DataManager.CreateTable<PanelLog>();
DataManager.CreateTable<Trace>();
}
Basically, this works because the CreateTable method checks to see if the table already exists before creating it. However, I don't like the idea of frivolously running some code knowing it's going to fail because of some of some exception to its expectations. I'd prefer to be more explicit.
Therefore, how can I execute code the first time my app runs to test if the tables need to be created, and if so to create them? And any subsequent time my app runs it doesn't check that code.
This is what I use to create or upgrade my database, and it seems to work really well. It's a hack from various sources in the web. It creates 4 tables, unless they already exist. I haven't included the static variables but that should be clear enough to follow?
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DATABASE_CREATE);
db.execSQL(DATABASE_CREATE_2);
db.execSQL(DATABASE_CREATE_3);
db.execSQL(DATABASE_CREATE_LIST_SUB);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE);
db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE_2);
db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE_3);
db.execSQL("DROP TABLE IF EXISTS " + DATABASE_LIST_SUB);
onCreate(db);
}
}
You can use other data storage options in android.take a look at http://developer.android.com/guide/topics/data/data-storage.html#filesInternal.You may find any storage option that are specific and secure to be used by a single app and their lifetime will be until you uninstall the app.So store in it the information either you created database or not,and check that storage everytime you run that app.
Create your database at the main_activity if you want, you can even create it on the splash screen activity if you have one.
As long you don't change the tables names, they will be created only one time, which is the first time the class that contains create table commands is called.
UPDATE
Check this Website, there you ll find a very simle tutorial, a bit long but very helful, if you don't have time you can try to use the code for creating your tables.
I read some threads about topics similar to this one however I could not find any big information on it. I am trying to add a column to the existing database table, and read from it on the content provider class, but it is not going thru, on the DBHelper class I do the ALTER TABLE as follows
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion<2) {
db.execSQL("ALTER TABLE SongInfo ADD COLUMN playcount INTEGER DEFAULT 0");
}
}
my version number is 1, and when I run it it gets the column playcount does not exist, I am trying to get the column by calling for it on contentProvider class, is there something else to it? do I need to update in another part of the code or is it suppose to accept the ALTER TABLE and just make the column readable from start of program, thanks much.
try
db.beginTransaction();
db.execSQL("...");
db.setTransactionSuccessful();
I m following this tutorial.http://www.androidhive.info/2011/11/android-sqlite-database-tutorial/
can any body please make me clear this chunk of code.
// Creating Tables
#Override
public void onCreate(SQLiteDatabase db) {
String CREATE_CONTACTS_TABLE = "CREATE TABLE " + TABLE_CONTACTS + "("
+ KEY_ID + " INTEGER PRIMARY KEY," + KEY_NAME + " TEXT,"
+ KEY_PH_NO + " TEXT" + ")";
db.execSQL(CREATE_CONTACTS_TABLE);
}
// Upgrading database
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Drop older table if existed
db.execSQL("DROP TABLE IF EXISTS " + TABLE_CONTACTS);
// Create tables again
onCreate(db);
}
Questions
What is the purpose of onUpgrade(); method?
When it is Called? as docs says this is Called when the database needs to be upgraded what does it means by upgrading the database?
Important
why we drop the table in this method and recreate?
Thanks in advance.
onUpgrade is basically for handling new db changes(could be new columns addition,table addition) for any new version of your app.
Droping the table is not always necessary in onUpgrade it all depends on what your use case is. If the requirment is to not to persists the data from your older version of app then drop should help,but if its like changing schema then it should only have alter scripts.
Upgrade means changes have been made to the database schema(version numbers are different) and it needs to be upgraded. Dropping the table and recreating is one way to do that. You could also issue "alter table" statements.
When you open your database it checks the version number and whether or not it exists. You can just "upgrade" your database rather than creating it new.
A good tutorial: http://www.vogella.com/articles/AndroidSQLite/article.html
This method is called when you update your database version. It drops the existing tables and creates it again when onCreate method is called again.
Replying to your 4 questions:
1) The purpose of onUpgrade is to manage a new database structure. You could start you app with simple features, then you need for instance to add a new column, so you need to increase the version of your database from 1 to 2 and in onUpgrade
give the instruction to add a new column, so that if the user update the app, the new column become added.
2) onUpgrade is called when you have a new version of your database and you incremented the int number in the super method( here is 1, so you eventually change it to 2)
public static class DatabaseHelper extends SQLiteOpenHelper{
DatabaseHelper(Context context){
super (context,DATABASE_NAME,null,1);
}
3) Please see above regarding what does it means to update the db
4) We Drop the table and recreate, because to modify the table (example for adding a new column that fits a new feature) a logic way to proceed could be, before to "destroy"/DROP the table and then create a new one with all the data. But this can be not the way to go although recreating the data could mean that the id numbers will be consecutive( usually are not consecutive: you could have 1, 2, and..4 because 3 has been deleted), hence dropping and then creating the table again, and eventually loading the previous data you could have this id consistency.
Sometimes you may want to use ALTER instead of DROP. Why? Usually because using DROP the user loses the content already has in the database, then if you want to learn more about Best practices and more complex real life scenarios please have a look at this amazing reply