The best way to overwrite an SQLite database table in Android? - android

When there is new data available to my Android application I need to completely remove all current entries in one of the SQLite database tables and replace them all with the new data. What is the best way to do this?
Would it be best to run
DELETE * FROM my_table
or
run a delete query for every row in the database
or run
database.execSQL(DATABASE_DROP_MY_TABLE);
database.execSQL(DATABASE_CREATE_MY_TABLE);
Where DATABASE_DROP_MY_TABLE is SQL to drop the table and DATABASE_CREATE_MY_TABLE is
SQL to create the table again with no entries.
And then following one of these, insert the new data.
Of course there are probably other ways to do this that I have not thought of.

Assuming you're using SQLiteOpenHelper, you can just close db, delete the whole file and recreate the db:
class MyDatabase extends SQLiteOpenHelper {
public static final String DB_NAME = "wat";
public MyDatabase(Context context) {
super(context, DB_NAME, null, CURRENT_VERSION);
}
}
dbHelper.close(); // dbHelper is your MyDatabase instance
context.deleteDatabase(DB_NAME);
SQLiteDatabase db = dbHelper.getWritableDatabase() // will create empty db
Nice thing about this solution is that you won't have to update table resetting code when you add new tables to your schema. It also correctly recreates indexes you might have added.

I wouldn't complicate things, and simply drop the table with DROP TABLE statement. As the doc say:
The SQLite DROP TABLE statement is used to remove a table definition and all associated data, indexes, triggers, constraints and permission specifications for that table.
You would have clean plate, then create the table again and add your new data.

Related

Creating new tables automatically vs Giant table

Im receiving throught BLE data stored in an SD Card. This data is organized in multiple text files, with each file corresponding to a date.
When receiving this data on android i want to save it on a SQlite database.
Thought about using the same logic, creating a table for each day. My question is if its possible to automatically create tables depending on the number of days that is going to be transfered. After some research i found how to add new tables using the onUpgrade method and changing the database version, but this seems only possible by changing the database version manually.
Another option would be by creating a single table for all the data, and add the date as a column.
Any feedback is valuable!
Typically you would use a single table with the date as a column.
It would be possible to dynamically create tables, if they don't exist outside of the onUpgrade method. For each date/file you could, when receiving the file and before loading/inserting the data, either :-
use CREATE TABLE IF NOT EXISTS the_table_with_a_name_that_relates_to_the_date (the_column_definitions)
i.e. if the table exists then the above is effectively a NOOP.
use something like (the below assumes this method is in the DatabaseHelper)
:-
public bolean checkAndAddTable(String tableName) {
boolean rv = false;
SQLiteDatabase = this.getWriteableDatabase();
Cursor csr = db.query("sqlite_master",null,"name=? AND type='table'",new String[]{tableName},null,null,null);
if (csr.getCount() < 1) {
db.execSQL("CREATE TABLE IF NOT EXISTS " + tableName + "(......SQL TO CREATE THE COLUMN DEFINITIONS......)");
rv = true;
}
csr.close();
return rv;
}
Note the code is in-principle code ans has not been run or tested and my therefore have some errors.
However, extracting the data from multiple tables would/should need to check if the table exists, to see if data can be extracted which would incur additional processing/complications (e.g. what to do if it doesn't exist).

Adding column in room db

I have been going through Room DB introduced in new architecture components in Android and thinking about migrating my current DBs to Room DBs.
But my current db implementation allows me to add columns to the table but as per Room, fields in POJO class represents the columns of table.
It is possible to add columns in Room DB using raw query, if yes, how shall I implement it.
I know this is an old post, but this might help someone out there that needs help with this.
Do you want to add said column on an upgrade of a DB or would you like to do it on first creation of the table?
If you want to do it on an upgrade of the DB then you can look at
Migrating Room databases
Room.databaseBuilder(getApplicationContext(), MyDb.class, "database-name")
.addMigrations(MIGRATION_1_2, MIGRATION_2_3).build();
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
#Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("CREATE TABLE `Fruit` (`id` INTEGER, `name` TEXT, PRIMARY KEY(`id`))");
}
};
static final Migration MIGRATION_2_3 = new Migration(2, 3) {
#Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE Book ADD COLUMN pub_year INTEGER");
}
};
If you want to add the column on the fly you will have to get the instance of your DB then can try call the following:
getDatabaseInstance().query()
There is little point for using Room with this table. After all, you cannot dynamically modify any entities or DAO methods, and so Room will not know anything about these changed columns.
If the rest of your database is Room-friendly, and you just have this one weird table, you can call getOpenHelper() on your RoomDatabase to get the SupportSQLiteOpenHelper, then work from there. The SupportSQLite... classes resemble the native Android SQLite API.

Android upgrading a DB with a NOT NULL column - what happens to old users

I have an app released in app store
I want to add a new column to the user table in the sqlite db and want it to be not null
But I also want old users to be able to use the app
What will happen if an old user updates their app with the new version? At login, I get the info from the server and I insert it in the db. The db insertion will probably stop when there is no value for the new column
Also, how do I do the upgrade itself?
in onUpgrade I do "ALTER table USER..."
in the constructor of the SQLite helper I add the new DB version
what else?
Also, I've added 3-4 totally new tables needed for new features. I've called their create queries in the onCreate method of the SQLite helper. Should I do anything else in addition to this?
in the constructor of the SQLite helper I add the new DB version
That will trigger onUpgrade(), good.
However, you cannot use ALTER TABLE to add a column with NOT NULL.
Here's what you can do in onUpgrade() to preserve user data:
Rename the old table to a temporary name
Recreate the table with the new column and NOT NULL
Populate the new table from the old temp table and supply the new column a reasonable non-null default value
Drop the temporary table
Can you give me an example lets say table is called USER with fields NAME and EMAIL and now I want to add a new field AGE?
Here's an example:
sqlite> create table user(name, email);
sqlite> insert into user select 'foo','bar';
sqlite> alter table user rename to user_temp;
sqlite> create table user(name, email, age not null);
sqlite> insert into user select name,email,-1 from user_temp;
sqlite> drop table user_temp;
sqlite> select * from user;
name|email|age
foo|bar|-1
Also, I've added 3-4 totally new tables needed for new features. I've called their create queries in the onCreate method of the SQLite helper. Should I do anything else in addition to this?
should I put the new creates for the new tables in both onCreate and onUpgrade or only in onUpgrade?
Make sure the same new tables are created in onUpgrade().
onCreate() is only run when the database is created for the first time, not on upgrade.
After both onCreate() and onUpgrade() the database schema (table structure) should be compatible. How you implement it is up to you. Putting the CREATE TABLEs there in onUpgrade() is an option. Some people prefer to call onCreate() insinde onUpgrade(), which can cause some headache when trying to migrate old data.

About the update of SQLite in Android

About the update of SQLite in Android.When you change the structure of the datebase,how can we update the datebase without delete the data?
You should override the onUpgrade Method in the SQLiteOpenHelper. You should code something like this.
public void onUpgrade (SQLiteDatabase db,int oldVersion,int newVersion){
String update = ALTER TABLE <table_name> ADD COLUMN <column_name> <column_type>;
db.execSQL(update);
}
Dropping a table, adding a row, inserting/updating/deleting data should be done here.
Alter Table gives you very limited options in performing an update to the database tables. If you want to copy your data into a completely new structure, you should think about creating temporary tables where you can copy data, create the new schema and then copy your data from the temporary tables to the new table, in this upgrade method.
Make sure you have your DB Version numbers correctly updated while creating the DBHelper.

Android onUpgrade() fails because database is locked, what should I do differently?

I have a project with a set of classes that are responsible for their respective database tables.
Each table managing class contains CRUD methods that follow the pattern of get connection, run crud operation, close connection:
public class PersonManager {
SQLiteDatabase db;
DbAdapter dbAdapter; //This is a subclass of SQLiteOpenHelper
public void addPerson(Person person)
{
ContentValues contentValues = new ContentValues();
contentValues.put("email", person.email);
contentValues.put("first_name", person.firstName);
db = dbAdapter.getWritableDatabase();
db.insert("person", null, contentValues);
db.close();
}
...other crud/utility methods omitted...
}
Now that I am upgrading my database via onUpgrade(), I run into database locked issues.
The exact error message follows:
CREATE TABLE android_metadata failed
Failed to setLocale() when constructing, closing the database
android.database.sqlite.SQLiteException: database is locked
It appears that onUpgrade is either meant to:
1 run db.execSQL() calls or
2 use helper classes that use onUpgrade()'s SQLiteDatabase rather than their own
It would be much easier to use my table managing classes to migrate data in onUpgrade() than db.execSQL() statements, or rewrite all my CRUD methods to take onUpgrade()'s SQLiteDatabase.
Am I setting up my database access correctly? If the above code follows the correct pattern, what should I do to fix this issue?
Thanks!
Here's your problem:
db = dbAdapter.getWritableDatabase();
When you're in onUpgrade(), you have to use the SQLiteDatabase handle that onUpgrade() provides you. So your solution is to rewrite your addPerson function to take one more argument -- an SQLiteDatabase handle:
public void addPerson(Person person, SQLiteDatabase db) {...}
If you need to call addPerson() from elsewhere in your project, then keep your current addPerson(Person person) function, have it do that
db = dbAdapter.getWritableDatabase()
call, and pass db to your two-argument version of addPerson().
I didn't get any answers, so I asked on a dev hangout.
According to the Android Developer Hangout Team, onUpgrade is only meant for structure alterations, not really for data migration/manipulation.

Categories

Resources