I have got 2 tables. Headers with names and details with texts:
create table Headers (_id integer primary key autoincrement, name string);
create table Details (_id integer primary key autoincrement, id_headers integet, text string);
id_headers is the link to table Headers row (one-to-many).
I want to write a method to upgrade these tables. The first and the least case I know is to create a temp table copy of 1st and 2nd tables, create new structure and insert data into new structure.
But in this case all "id_headers to _id" relations will be lost.
How can I keep them in new structure, and the same time I want them to keep as "autoincrement".
SQLiteDatabase.insert returns the new _id. Insert the Headers table data first, creating a mapping of new _id's against _id's in temp data structure.
Now when you populate the Details table consult your map for the old id_headers value to get the new id_headers value.
private void migrate(SQLiteDatabase db){
ArrayList<Header> oldHeaders = new ArrayList<Header>();
ArrayList<Detail> oldDetails = new ArrayList<Detail>)();
HashMap<Long,Long> idMap = new HashMap<Long,Long>();
Cursor oldHeadersCurs = db.query("Headers", null, null, null, null, null, null);
oldHeadersCurs.moveToFirst();
//store the old header records
while (!oldHeadersCurs.isAfterLast()){
long oldId = oldHeadersCurs.getLong(oldHeadersCurs.getColumnIndex("_id"));
String name = oldHeadersCurs.getString(oldHeadersCurs.getColumnIndex("name"));
oldHeaders.put(new Header(oldId,name));
oldHeadersCurs.moveToNext();
}
//delete the headers table
db.execSQL("DROP TABLE Headers");
//create the new headers table
db.execSQL(CREATE_NEW_HEADERS_TABLE_STMT);
//insert the header records capturing the new id
for (Header header : oldHeaders){
ContentValues cv = new ContentValues();
cv.put("name", header.getName());
long newId = db.insert("Headers", null, cv);
idMap.put(header.getId(), newId); //mapping the old _id to the new
}
//store the old detail records
Cursor oldDetailsCurs = db.query("Details", null, null, null, null, null, null);
oldDetailsCurs.moveToFirst();
while (!oldDetailsCurs.isAfterLast()){
//btw text is a data type in sqlite, you need to rename this column
String text = oldDetailsCurs.getString(oldDetailsCurs.getColumnIndex("text"));
long oldHeaderId = oldDetailsCurs.getLong(oldDetailsCurs.getColumnIndex("id_headers"));
oldDetails.put(new Detail(text,oldHeaderId));
oldDetails.moveToNext();
}
//recreate details table
db.execSQL("DROP TABLE Details");
db.execSQL("CREATE_NEW_DETAILS_TABLE_STMT");
//insert the new detail records using the id map
for (Detail detail : oldDetails){
ContentValues cv = new ContentValues();
cv.put("text",detail.getText());
cv.put("id", idMap.get(detail.getHeaderId())); //retrieving the new _id based on the old
db.insert("Details", null, cv);
}
}
Related
I want to swap sqlite data
now, I am changing data after saving it in a variable
Is there a better way? Thank you
updateDbDate(fromItem.getTitle(),fromItem.getCable(),fromItem.getImg(),toItem.getId());
updateDbDate(toItem.getTitle(),toItem.getCable(), toItem.getImg(),fromItem.getId());
public void updateDbDate(String mTitle, String mCable, String mImg, int id)
{
ContentValues values = new ContentValues();
values.put("title", mTitle);
values.put("cable", mCable);
values.put("bimg", mImg);
db.update(Define.DB, values,"_id = " + "'" + id + "'",null);
}
What I understand is that you want to swap the values of 3 columns between 2 rows for which you know the ids.
If you also know the values of the other 3 columns then your method is correct.
If you don't know them and you have to read them from the table then I think it would be better to just swap the ids:
public void swapIds(int id1, int id2) {
ContentValues values = new ContentValues();
values.put("_id", -1);
db.update(Define.DB, values, "_id = ?", new String[] {String.valueOf(id1)});
values.put("_id", id1);
db.update(Define.DB, values, "_id = ?", new String[] {String.valueOf(id2)});
values.put("_id", id2);
db.update(Define.DB, values, "_id = ?", new String[] {"-1"});
db.close();
}
The 1st update sets temporarily -1 to the first _id, because I guess it is the PRIMARY KEY and it can't be set to id2 because it already exists.
The 2nd update sets id1 to the second _id (it can be done since id1 does not exist in the table from the previous update).
And the 3d update sets id2 to the first _id.
Now you can call the method:
swapIds(100, 200);
Note: this method is not recommended if there are references in other tables to the _id of this table.
For example I have a table named myTable in my database file (Android, p.s. it doesn't support column renaming, deleting and so on).
This table has idx, name columns
I want to delete and recreate this table but with new columns
Here how I do it:
db.transaction {
var cursor = query("myTable", null, null, null, null, null, null)
// save info to a list and insert it later to a recreated table with new columns
cursor.close()
// delete table "myTable"
execSQL("DROP TABLE IF EXISTS myTable")
// create table "myTable" but with new columns
execSQL("CREATE TABLE myTable(id, title)")
// get columns
cursor = query("myTable", null, null, null, null, null, null)
val columnNames = cursor.columnNames
cursor.close()
Log.i(TAG, "columns of new table ${Arrays.toString(columnNames)}")
}
But cursor.columnNames doesn't return new columns (id, title)
It returns the old columns (e.g., idx, name)
Though when I close the app and open again everything is ok (old columns are gone and new ones are available)
So annoying!
So new columns are created ok in main.db/myTable during all this process but seems the app still keeps old columns in memory
I can't even use cursor.getString(cursor.getColumnIndex("title")) (would return -1) because it still thinks that this column doesn't exist yet until I restart this app
BUT! Recreating a table with new columns works fine if I don't use cursor to backup data (info) before I delete the old table
db.transaction {
// !! I COMMENTED THESE LINES
// var cursor = query("myTable", null, null, null, null, null, null)
// save info to a list and insert it later to a recreated table with new columns
// cursor.close()
// delete table "myTable"
execSQL("DROP TABLE IF EXISTS myTable")
// create table "myTable" but with new columns
execSQL("CREATE TABLE myTable(id, title)")
// get columns
cursor = query("myTable", null, null, null, null, null, null)
val columnNames = cursor.columnNames
cursor.close()
Log.i(TAG, "columns of new table ${Arrays.toString(columnNames)}")
}
In this case cursor.columnNames returns new columns id, title
This is crazy!
So it seems query table1, drop table1, create table1, query table1 sequence would lead to an unexpected behavior
And we can only do drop table1, create table1, query table1 sequence
I'm using SQlite in my Android app and the task is - how can I update all the rows in one table?
I have a 1st column with name "cl_id" (integer numbers 1-2-3-4..) and after deleting some rows, I wan't to make a cycle to fill this 1st column with a new values to keep them in right order.
I was trying to execute:
data.put("cl_id",index);
db.update("mdb_table_contactList", data, null, null);
but it's updates all the values in the first column :(
To update the field in specific row, try this;
ContentValues data = new ContentValues();
data.put("cl_id",index);
db.update("mdb_table_contactList", data, "id="+_id, null);
db.close();
It's good practice to have a primary key for each row data.
Here _id would be your primary key.
"just give rowId and type of data that is going to be update in ContentValues."
public void updateStatus(String id , int status){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues data = new ContentValues();
data.put("status", status);
db.update(TableName, data, "columnName" + " = "+id , null);
}
Try this it must work
void updateDatail(String id) {
ContentValues data = new ContentValues();
data.put("cl_id",index);
db.update("mdb_table_contactList", data, "id=?", new String[]{id});
db.close();
}
I wrote a rssFeedReader Application and use directly sqliteSyntax to modify database.
this is my code:
database.execSQL database= openOrCreateDatabase("MyDB", MODE_PRIVATE, null);
database.execSQL("Create TABLE IF NOT EXISTS Press (press_name
VARCHAR, press_url VARCHAR");
database.execSQL("INSERT INTO Press VALUES ('Tasnim',
'http://www.tasnimnews.com/english/rss/feed/?d=2&c=1&m=6&alt=Recent%20News');");
database.execSQL("UPDATE Press press_name ='Tasnim',
press_url ='http://www.tasnimnews.com/english/rss/feed/?
d=2&c=1&m=6&alt=Recent%20News');");
Cursor cursor = database.rawQuery("SELECT * FROM MyTable", null);
database.close();
and now my question is how can I migrate to SQLiteOpenHelper and ConentValues method to modify database.
// Gets the data repository in write mode
SQLiteDatabase db = mDbHelper.getWritableDatabase();
// Create a new map of values, where column names are the keys
ContentValues values = new ContentValues();
values.put(FeedEntry.COLUMN_NAME_ENTRY_ID, id);
values.put(FeedEntry.COLUMN_NAME_TITLE, title);
values.put(FeedEntry.COLUMN_NAME_CONTENT, content);
// Insert the new row, returning the primary key value of the new row
long newRowId;
newRowId = db.insert(
FeedEntry.TABLE_NAME,
FeedEntry.COLUMN_NAME_NULLABLE,
values);
You can find it here http://developer.android.com/training/basics/data-storage/databases.html
I am developing my first application which contains an SQLite database, containing table ANIMAL which has the columns _id, animal_name, animal_bio.
The user is presented with animal names in a ListView; selecting an animal will bring him/her to a page where he/she can view the animals bio.
The problem I'm having is:
When I add the bio of each animal to the DB - no errors.
However, running the app causes the ListView (previously working) to display a blank screen.
My Insertion code:
public long populateDB(){
ContentValues initialValues = new ContentValues();
long[] rowIds = new long[animalName.length];
// Populate the animal table
for(int i = 0; i < animalName.length; i++){
initialValues.put(KEY_ANIMALNAME, animalName[i]);
initialValues.put(KEY_BIOGRAPHY, bio[i]);
rowIds[i] = qmDB.insert(ANIMAL_TABLE, null, initialValues);
}
return rowIds[0];
}
And the create database statement
private static final String DATABASE_CREATE =
"create table " + ANIMAL_TABLE +
" (_id integer primary key autoincrement, " +
"animal_name text not null, " +
"biography text not null);";
I cannot see anything wrong with this code, so if anyone has any suggestions, I'd be very grateful.
EDIT: Retrieving animals code
public Cursor retrieveAnnimals(){
return qmDB.query(ANIMAL_TABLE, new String[] {
KEY_ROWID,
KEY_ANIMALNAME,
},
null,
null,
null,
null,
ORDER_BY_NAME);
}
Calling the create and insert from application, this takes place in the ListActivity, called ListAnimals:
dbm = new MyDBManager();
dbm.open();
dbm.deleteTable();
dbm.populateTable();
myCursor = dbm.retrieveAnimals();