How do I delete column from table in room database? - android

How do I delete column from table in room database android.I alredy try all the way drop and delete not working.
This code also not working:-
static final Migration MIGRATION_3_4 = new Migration(3, 4)
{
#Override
public void migrate(SupportSQLiteDatabase database)
{
database.execSQL("CREATE TABLE users_new (userid TEXT, username TEXT, last_update INTEGER, PRIMARY KEY(userid))");
// Copy the data
database.execSQL("INSERT INTO users_new (userid, username, last_update) SELECT userid, username, last_update FROM users");
// Remove the old table
database.execSQL("DROP TABLE users");
// Change the table name to the correct one
database.execSQL("ALTER TABLE users_new RENAME TO users");
}
};

Android ROOM is based on SQL Lite which does not allow dropping database table columns. Instead you have to:
create a temporary table without the column you are trying to delete,
copy all records from old table to new table,
drop the old table,
rename new table to same name as old table
See related question:Sqlite Dropping Column from table

Related

Android - Change a column type in SQLite database dynamically at runtime

I have an application, where I am detecting the type of a particular column at run-time, on page load. Please refer the below code:
public String fncCheckColumnType(String strColumnName){
db = this.getWritableDatabase();
String strColumnType = "";
Cursor typeCursor = db.rawQuery("SELECT typeof (" + strColumnName +") from tblUsers, null);
typeCursor.moveToFirst();
strColumnType = typeCursor.getString(0);
return strColumnType;
}
The above method simply detects the type of column with column Name 'strColumnName'. I am getting the type of column in this case.
Now, I want to change the column type to TEXT if I am receiving INTEGER as the column type. For this, I tried the below code:
public String fncChangeColumnType(String strColumnName){
db = this.getWritableDatabase();
String newType = "";
Cursor changeCursor = db.rawQuery("ALTER TABLE tblUsers MODIFY COLUMN " + strColumnName + " TEXT", null);
if (changeCursor != null && changeCursor.moveToFirst()){
newType = changeCursor.getString(0);
}
return newType;
}
But while executing the 'fncChangeColumnType' method, I am getting this error, android.database.sqlite.SQLiteException: near "MODIFY": syntax error (code 1): , while compiling: ALTER TABLE tblUsers MODIFY COLUMN UserID TEXT
NOTE: I also replaced 'MODIFY' with 'ALTER', but still getting the same error.
Please check if this is the right method to change the type dynamically.
Please respond back if someone has a solution to this.
Thanks in advance.
In brief, the solution could be :-
Do nothing (i.e. take advantage of SQLite's flexibility)
you could utilise CAST e.g. CAST(mycolumn AS TEXT) (as used below)
Create a new table to replace the old table.
Explanations.
With SQLite there are limitations on what can be altered. In short you cannot change a column. Alter only allows you to either rename a table or to add a column. As per :-
SQL As Understood By SQLite - ALTER TABLE
However, with the exception of a column that is an alias of the rowid column
one defined with ?? INTEGER PRIMARY KEY or ?? INTEGER PRIMARY KEY AUTOINCREMENT or ?? INTEGER ... PRIMARY KEY(??) (where ?? represents a valid column name)
you can store any type of value in any type of column. e.g. consider the following (which stores an INTEGER, a REAL, a TEXT, a date that ends up being TEXT and a BLOB) :-
CREATE TABLE IF NOT EXISTS example1_table (col1 BLOB);
INSERT INTO example1_table VALUES (1),(5.678),('fred'),(date('now')),(x'ffeeddccbbaa998877665544332211');
SELECT *, typeof(col1) FROM example1_table;
The result is :-
As such is there a need to change the column type at all?
If the above is insufficient then your only option is to create a new table with the new column definitions, populate it if required from the original table, and to then replace the original table with the new table ( a) drop original and b)rename new or a) rename original, b) rename new and c) drop original)
e.g. :-
DROP TABLE IF EXISTS original;
CREATE TABLE IF NOT EXISTS original (mycolumn INTEGER);
INSERT INTO original VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(0);
-- The original table now exists and is populated
CREATE TABLE IF NOT EXISTS newtable (mycolumn TEXT);
INSERT INTO newtable SELECT CAST(mycolumn AS TEXT) FROM original;
ALTER TABLE original RENAME TO old_original;
ALTER TABLE newtable RENAME TO original;
DROP TABLE IF EXISTS old_original;
SELECT *,typeof(mycolumn) FROM original;
The result being :-
i think the sql query statement is wrong ,try
ALTER TABLE tblUsers MODIFY COLUMN id TYPE integer USING (id::integer);
instead of id use column name....
hope this helps....
EDIT:
"ALTER TABLE tblUsers MODIFY COLUMN "+strColumnName+" TYPE integer USING ("+strColumnName+"::integer);"

Sqlite column fails to create in creation time

I'm facing a strange problem. I'm creating a db in sqlite with the below query
String GROUP_TABLE = "groups";
String ROW_ID = "rowid";
String GROUP_ID = "GroupID";
String GROUP_NAME = "GroupName";
String GROUP_STATUS = "GroupStatus";
String IS_ADMIN = "IsAdmin";
String GROUP_TYPE = "GroupType";
String IS_PUBLIC = "IsPublic";
String LAST_UPDATE = "LastUpdate";
String groupQuery = "CREATE TABLE IF NOT EXISTS "+ GROUP_TABLE +" ("
+ROW_ID+" INTEGER PRIMARY KEY, "
+GROUP_ID+" TEXT, "
+GROUP_NAME+" TEXT, "
+GROUP_STATUS+" TEXT, "
+GROUP_TYPE+" TEXT, "
+IS_ADMIN+" TEXT, "
+IS_PUBLIC+" TEXT, "
+LAST_UPDATE+" TEXT);";
This is the schema given by sqlite adb command
H:\adt-bundle-windows-x86_64-20140702\sdk\platform-tools>sqlite3
SQLite version 3.8.10.2 2015-05-20 18:17:19
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> .open mydb.db
sqlite> .full schema
Usage: .fullschema
sqlite> .fullschema
CREATE TABLE android_metadata (locale TEXT);
CREATE TABLE groups (rowid INTEGER PRIMARY KEY, GroupID TEXT, GroupName TEXT, GroupStatus TEXT, GroupType TEXT, IsAdmin TEXT, IsPubli
c TEXT, LastUpdate TEXT);
/* No STAT tables available */
and when I enter records for the first time there will be no problem. But when I try to enter records next time i get
E/SQLiteLog﹕ (1) table groups has no column named LastUpdate
11-04 14:35:01.850 11947-11974/? E/SQLiteDatabase﹕ Error inserting GroupType=1 GroupID=553 LastUpdate=2015-08-08T14:17:14.000Z IsAdmin=1 GroupName=SAIFOOTWEARS GroupStatus=1
android.database.sqlite.SQLiteException: table groups has no column named LastUpdate (code 1): , while compiling: INSERT INTO groups(GroupType,GroupID,LastUpdate,IsAdmin,GroupName,GroupStatus) VALUES (?,?,?,?,?,?)
And when I check the schema again the column is missing.
H:\adt-bundle-windows-x86_64-20140702\sdk\platform-tools>sqlite3
SQLite version 3.8.10.2 2015-05-20 18:17:19
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> .open mydb.db
sqlite> .fullschema
CREATE TABLE android_metadata (locale TEXT);
CREATE TABLE groups ( rowId INTEGER PRIMARY KEY,GroupID TEXT, GroupName TEXT,GroupStatus TEXT,IsAdmin TEXT, GroupType TEXT, IsPublic
TEXT);
/* No STAT tables available */
Any leads on this would be of great help.
onCreate() method of sqliteOpenHelpers called when the database is created for the first time. This is where the creation of tables and the initial population of the tables should happen.
I think first time when you created your database you don't include LastUpdate column. Later you included it.but your table is created first time.So when adb get same database version for your app it dose not update your database.
So try this
Change your databse version no. Or uninstall app from your phone and run it again.
If problem does not solve.Then please provide full code of your class in Question.

Add new Column to Android SQLite Database Create new table

I want to add columns to table, i search before topics.
Seem they like to alert table. But i perfer to create new table.
So I try to do like this
`
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
db.execSQL("create table tmp_talbe name VARCHAR(50),number integer,number2 integer");
db.execSQL("insert into tmp_table select * from origin_table");
db.execSQL("drop if exists table origin_table");
db.execSQL("alter tmp_talbe rename to origin_talbe");
}`
I have problem in copy old table data to new table.If i have 2 columns in old table, 3 colums in new table,
.It will show error 3 columns in tmp_table, but only 2 supplier.
Seem code line 2 can't do like this,how to modify is better?
You got the error because 'select * from origin_table' only return 2 columns, NOT 3 columns and tmp_table has 3 columns.
I assume that the original table columns: NAME, Number1 and You want to add Number2 as third column:
Change
db.execSQL("insert into tmp_table select * from origin_table");
To
db.execSQL("insert into tmp_table select NAME, Number1, NULL as Number2 from origin_table");
Use NULL for third column when you copy data from Original table to Temp table.
You can also use any Default data for Third column.

How to make dynamic column using Android SQLite Database

Im writing application on Android and im using SQlite database.
I want to be able to add columns to my table by the user choice.
so the user can add any column that he wants the to table. For example the user have "animal" table and he want to add column for "dog", "cat" and "fish".
I have read about some solutions and i didnt saw one that can help me.
I read that the simple way to add column is using:
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// If you need to add a column
if (newVersion > oldVersion) {
db.execSQL("ALTER TABLE " + TableName + " ADD COLUMN " + ColumnName);
}
}
But my problem with this that i cant choose what is the name of the column that will be added to the table by the user choise, there is no parameter for string.
So i tried using something like this, and to call it directly.
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion, String newColumnName) {
// If you need to add a column
if (newVersion > oldVersion) {
db.execSQL("ALTER TABLE " + TableName + " ADD COLUMN " + newColumnName);
}
}
But i got error for this method.
I have another question about the database version.
The onUpgrade method get automaticly called when onCreate get called.
In onUpgrade there is oldVersion and newVersion parameters for the database version. when do i set the oldVersion and newVersion parameters? How i set my newVersion parameter to 2,3,4...?
You can create an auxiliary table to hold the extra column data. Queries to your primary table can be converted into queries on a new view.
create table if not exists animal (pk integer primary key, name);
create table if not exists animal_aux (animal_pk, col_name, col_val);
create view if not exists animal_view
as select animal.name as name,
ct.col_val as cat,
dt.col_val as dog
from animal, animal_aux as ct, animal_aux as dt
where animal.pk = ct.animal_pk
and animal.pk = dt.animal_pk
and ct.col_name = 'cat'
and dt.col_name = 'dog'
;
This schema should be enhanced to make animal_pk, col_name a primary key, or at least unique in animal_aux. You may also need triggers to add or remove entries in the aux table when you insert or delete entries in the animal table.
Example:
sqlite> select * from animal_view;
sqlite> insert into animal values (NULL, 'fred');
sqlite> select * from animal_view;
sqlite> select * from animal;
1|fred
sqlite> insert into animal_aux values (1, "dog", "beagle");
sqlite> insert into animal_aux values (1, "cat", "siamese");
sqlite> select * from animal_view;
fred|siamese|beagle
sqlite>
Each time you add a virtual column, you'll need to
drop view animal_view;
and then re-create it with the appropriate extra columns and where clauses.
final static String Database_name="empDb.db";
public DatabaseHelper(Context context) {
super(context, Database_name, null, 1);
}
#Override public void onCreate(SQLiteDatabase db) {
db.execSQL("create table emp_tbl (id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT,salary TEXT)");
}
#Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS tbl_emp");
}
blog: https://itmulc.blogspot.com/2016/08/android-sqlite-database-with-complete.html
Get more info about it.
https://www.youtube.com/watch?v=W8-Z85oPNmQ

Android SQLite Upgrade without losing data

I have created a SQLite database successfully and it works fine. However when the onUpgrade method is called, I'd like to do so without losing data. The app I'm developing is a quiz app. Simply, when the onCreate method is called I create and prepopulate a database with questions, answers etc. The last column is whether they have set the question as a favourite or not. What I would like to do is that when the onUpgrade method is called, I'd like to temporarily save that one column, drop the whole database, recreate it with any edits I've made to old questions and add any new questions then re-add back the questions that they set as favourites.
So one option I tried was the following:
db.execSQL("ALTER TABLE quiz RENAME TO temp_quiz");
onCreate(db);
db.execSQL("INSERT INTO quiz (favouries) SELECT favourites FROM temp_quiz");
db.execSQL("DROP TABLE IF EXISTS temp_quiz");
However this doesn't work owing to the fact INSERT INTO just adds new rows rather than replacing the existing rows. I have also tried REPLACE INTO, INSERT OR REPLACE INTO and
db.execSQL("INSERT INTO quiz (_id, favouries) SELECT _id, favourites FROM temp_quiz");
of which none work.
Currently I do have it set up to work by altering the name of the table, calling the onCreate(db) method and then setting up a cursor which reads each row and uses the db.update() method as shown below:
int place = 1;
int TOTAL_NUMBER_OF_ROWS = 500;
while (place < TOTAL_NUMBER_OF_ROWS) {
String[] columns = new String[] { "_id", ..........., "FAVOURITES" };
// not included all the middle columns
Cursor c = db.query("temp_quiz", columns, "_id=" + place, null, null, null, null);
c.moveToFirst();
String s = c.getString(10);
// gets the value from the FAVOURITES column
ContentValues values = new ContentValues();
values.put(KEY_FLAG, s);
String where = KEY_ROWID + "=" + place;
db.update(DATABASE_TABLE, values, where, null);
place++;
c.close();
}
However whilst this works it is extremely slow and will only get worse as my number of questions increases. Is there a quick way to do all this?
Thank you! P.S. Ideally it should only update the row if the row is present. So if in an upgrade I decide to remove a question, it should take this into account and not add a new row if the row doesn't contain any other data. It might be easier to get it to remove rows that don't have question data rather than prevent them being added.
changed it to:
db.execSQL("UPDATE new_quiz SET favourites = ( SELECT old_quiz.favourites
FROM old_quiz WHERE new_quiz._id = old_quiz._id) WHERE EXISTS
( SELECT old_quiz.favourites FROM old_quiz WHERE new_quiz._id = old_quiz._id)");
Which works :D
public class DataHelper extends SQLiteOpenHelper {
private static final String dbName="dbName";
private Context context;
private SQLiteDatabase db;
private final static int version = 1;
public static final String SurveyTbl = "CREATE TABLE SurveyTbl (SurveyId TEXT PRIMARY KEY, Idref TEXT, SurveyDate TEXT)";
public DataHelper(Context context) {
super(context, dbName, null, version);
this.db = getWritableDatabase();
this.context = context;
Log.i("", "********************DatabaseHelper(Context context)");
}
#Override
public void onCreate(SQLiteDatabase db) {
try {
db.execSQL(SurveyTbl);
} catch (Exception e) {
Log.i("", "*******************onCreate");
}
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
try {
db.execSQL("ALTER TABLE HandpumpSurveyTbl ADD COLUMN NalYozna TEXT");
} catch (Exception e) {
Log.i("", ""+e);
}
onCreate(db);
}
}
I didn't get to see your Quiz table schema, but I assume it has fields like "question", "answer", "favorites", and some kind of a unique primary key to identify each question, which I will just call rowId for now.
// after renaming the old table and adding the new table
db.execSQL("UPDATE new_quiz SET new_quiz.favorites = old_quiz.favorites where new_quiz.rowId = old_quiz.rowId");
That will update only the rows of the new quiz table that match the old quiz table, and set the favorites value from the old quiz table.
I assume you have some kind of a unique identifier to identify each question, so instead of the rowId above, you'll use that (question number or something).
For who don't know yet how to upgrade the version of the SQLite when upgrading the database schema for example, use the method needUpgrade(int newVersion)!
My code:
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
if(newVersion>oldVersion){
db.execSQL(scriptUpdate);
db.needUpgrade(newVersion);
}
}
ALTER TABLE mytable ADD COLUMN mycolumn TEXT
In your onUpgrade method, it would look something like this:
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
String upgradeQuery = "ALTER TABLE mytable ADD COLUMN mycolumn TEXT";
if (newVersion>oldVersion)
db.execSQL(upgradeQuery);
}
Example, how to drop a table and create a new table without losing data by using a temporary table:
db.execSQL("CREATE TEMPORARY TABLE temp_table (_id INTEGER PRIMARY KEY AUTOINCREMENT, col_1 TEXT, col_2 TEXT);");
db.execSQL("INSERT INTO temp_table SELECT _id, col_1, col_2 FROM old_table");
db.execSQL("CREATE TABLE new_table (_id INTEGER PRIMARY KEY AUTOINCREMENT, col_1 TEXT, col_2 TEXT, col_3 TEXT);");
db.execSQL("INSERT INTO new_table SELECT _id, col_1, col_2, null FROM temp_table");
db.execSQL("DROP TABLE old_table");
db.execSQL("DROP TABLE temp_table");

Categories

Resources