Upgrade SQLite database from one version to another? - java

I am getting an error from Logcat saying that a certain column (in my SQLiteOpenHelper subclass) does not exist. I thought I could upgrade the database by changing the DATABASE_CREATE string. But apparently not, so how can I (step-by-step) upgrade my SQLite Database from version 1 to version 2?
I apologize if the question seems "noobish", but I am still learning about Android.
#Pentium10 This is what I do in onUpgrade:
private static final int DATABASE_VERSION = 1;
....
switch (upgradeVersion) {
case 1:
db.execSQL("ALTER TABLE task ADD body TEXT");
upgradeVersion = 2;
break;
}
...

Ok, before you run into bigger problems you should know that SQLite is limited on the ALTER TABLE command, it allows add and rename only no remove/drop which is done with recreation of the table.
You should always have the new table creation query at hand, and use that for upgrade and transfer any existing data. Note: that the onUpgrade methods runs one for your sqlite helper object and you need to handle all the tables in it.
So what is recommended onUpgrade:
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
.
public static List<String> GetColumns(SQLiteDatabase db, String tableName) {
List<String> ar = null;
Cursor c = null;
try {
c = db.rawQuery("select * from " + tableName + " limit 1", null);
if (c != null) {
ar = new ArrayList<String>(Arrays.asList(c.getColumnNames()));
}
} catch (Exception e) {
Log.v(tableName, e.getMessage(), e);
e.printStackTrace();
} finally {
if (c != null)
c.close();
}
return ar;
}
public static String join(List<String> list, String delim) {
StringBuilder buf = new StringBuilder();
int num = list.size();
for (int i = 0; i < num; i++) {
if (i != 0)
buf.append(delim);
buf.append((String) list.get(i));
}
return buf.toString();
}

Here is how I upgrade my database.
In a previous version of my app, the gameType column doesn't exist. In the new version, it does.
void upgradeDatabase() throws IOException {
try {
String column = DatabaseConstants.GAME_TYPE_COLUMN_NAME; // gameType
String table = DatabaseConstants.RECORDS_TABLE;
String query = String.format("SELECT %s FROM %s LIMIT 1", column, table);
database.rawQuery(query, null);
return;
}
catch (Exception e) {
// Column doesn't exist. User had old version of app installed, so upgrade database.
}
// Save all old data
String query = "SELECT * FROM " + DatabaseConstants.USERS_TABLE;
Cursor c = database.rawQuery(query, null);
List<List<Object>> values1 = new ArrayList<List<Object>>();
if (c.moveToFirst()) {
while (!c.isAfterLast()) {
List<Object> record = new ArrayList<Object>();
record.add(c.getInt(0));
record.add(c.getString(1));
values1.add(record);
c.moveToNext();
}
}
c.close();
query = "SELECT * FROM " + DatabaseConstants.RECORDS_TABLE;
c = database.rawQuery(query, null);
List<List<Object>> values2 = new ArrayList<List<Object>>();
if (c.moveToFirst()) {
while (!c.isAfterLast()) {
List<Object> record = new ArrayList<Object>();
record.add(c.getInt(0));
record.add(c.getInt(1));
record.add(c.getInt(2));
record.add(c.getInt(3));
values2.add(record);
c.moveToNext();
}
}
c.close();
// Copy empty database with new schema
copyDatabase();
// Restore all old data
for (List<Object> record : values1) {
ContentValues cv = new ContentValues();
cv.put(DatabaseConstants.ID_COLUMN_NAME, (Integer) record.get(0));
cv.put(DatabaseConstants.USERNAME_COLUMN_NAME, record.get(1).toString());
database.insert(DatabaseConstants.USERS_TABLE, null, cv);
}
for (List<Object> record : values2) {
ContentValues cv = new ContentValues();
cv.put(DatabaseConstants.USER_ID_COLUMN_NAME, (Integer) record.get(0));
cv.put(DatabaseConstants.GAME_TYPE_COLUMN_NAME, GameType.CLASSIC.name());
cv.put(DatabaseConstants.WINS_COLUMN_NAME, (Integer) record.get(1));
cv.put(DatabaseConstants.LOSSES_COLUMN_NAME, (Integer) record.get(2));
cv.put(DatabaseConstants.TIES_COLUMN_NAME, (Integer) record.get(3));
database.insert(DatabaseConstants.RECORDS_TABLE, null, cv);
}
}
Here's the code to copy the database file. The database is initially empty, and I created it outside my app. (I used a program called Navicat for SQLite.)
public DatabaseHelper(Context context) {
super(context, DatabaseConstants.DATABASE_NAME, null, 1);
this.context = context;
databasePath = context.getDatabasePath(DatabaseConstants.DATABASE_NAME).getPath();
}
void copyDatabase() throws IOException {
InputStream is = context.getAssets().open(DatabaseConstants.DATABASE_NAME); // data.db
OutputStream os = new FileOutputStream(databasePath);
byte[] buffer = new byte[1024];
int length;
while ((length = is.read(buffer)) > 0) {
os.write(buffer, 0, length);
}
// Close the streams.
os.flush();
os.close();
is.close();
}

Wouldn't something like the following be easier for the vast majority of cases? Just add the new column for each version upgrade:
private static final String DATABASE_ALTER_TEAM_1 = "ALTER TABLE "
+ TABLE_TEAM + " ADD COLUMN " + COLUMN_COACH + " string;";
private static final String DATABASE_ALTER_TEAM_2 = "ALTER TABLE "
+ TABLE_TEAM + " ADD COLUMN " + COLUMN_STADIUM + " string;";
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < 2) {
db.execSQL(DATABASE_ALTER_TEAM_1);
}
if (oldVersion < 3) {
db.execSQL(DATABASE_ALTER_TEAM_2);
}
}
For a bit more on this, check out this blog.

Related

Data not delete using sqllite database

How to delete specific data using sqlite database via android.
db.delete("tbl_rmd", "rmd_typ = ? ", new String[]{id});
error : index not found
You must determine whether or not the data exists in the sqlite database.
public boolean checkIfRecordExist(String tableName, String columnName, String fieldValue) {
SQLiteDatabase database = this.getReadableDatabase();
String Query = "Select * from " + tableName + " where " + columnName + " =? ";
Cursor cursor = database.rawQuery(Query, new String[]{fieldValue});
if (cursor.getCount() <= 0) {
cursor.close();
return false;
}
cursor.close();
return true;
}
now modify your code like this...
if (checkIfRecordExist("tbl_rmd", "rmd_typ", id)) {
db.delete("tbl_rmd", "rmd_typ = ? ", new String[]{id});
}

Android : Duplicate contact data while retrieving contacts using ContactsContract.CommonDataKinds.Phone

I have gone through a lot of posts but didn't find any answer that answers the question efficiently or even correctly. The closest I came was this How to avoid duplicate contact name (data ) while loading contact info to listview? but this has too much overhead. Is there any simpler or more efficient way to solve this?
I had the same problem you had: I was getting duplicate phone numbers. I solved this problem by obtaining the normalized number for each cursor entry and using a HashSet to keep track of which numbers I'd already found. Try this:
private void doSomethingForEachUniquePhoneNumber(Context context) {
String[] projection = new String[] {
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER,
ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER,
//plus any other properties you wish to query
};
Cursor cursor = null;
try {
cursor = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projection, null, null, null);
} catch (SecurityException e) {
//SecurityException can be thrown if we don't have the right permissions
}
if (cursor != null) {
try {
HashSet<String> normalizedNumbersAlreadyFound = new HashSet<>();
int indexOfNormalizedNumber = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER);
int indexOfDisplayName = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
int indexOfDisplayNumber = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
while (cursor.moveToNext()) {
String normalizedNumber = cursor.getString(indexOfNormalizedNumber);
if (normalizedNumbersAlreadyFound.add(normalizedNumber)) {
String displayName = cursor.getString(indexOfDisplayName);
String displayNumber = cursor.getString(indexOfDisplayNumber);
//haven't seen this number yet: do something with this contact!
} else {
//don't do anything with this contact because we've already found this number
}
}
} finally {
cursor.close();
}
}
}
After API 21 We Write this Query for remove contact duplicacy.
String select = ContactsContract.Data.HAS_PHONE_NUMBER + " != 0 AND " +
ContactsContract.Data.MIMETYPE
+ " = " + ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE + "
AND "+ ContactsContract.Data.RAW_CONTACT_ID + " = " +
ContactsContract.Data.NAME_RAW_CONTACT_ID;
Cursor cursor = getContentResolver().query(ContactsContract.Data.CONTENT_URI, null, select,
null, null);
ContentResolver cr = this.getContentResolver();
String[] FieldList = {ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER,ContactsContract.CommonDataKinds.Phone.CONTACT_ID};
Cursor c = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,FieldList,
null,null,ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
String name,phone,ContactID;
HashSet<String> normalizedNumbers = new HashSet<>();
if(c!=null)
{
while(c.moveToNext()!=false)
{
phone = c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER));
if(normalizedNumbers.add(phone)==true)
{
name = c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
ContactID = c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID));
MyContacts m = new MyContacts(name,phone,ContactID);
ContactList.add(m);
}
}
c.close();

How to check existing SQLite db in Android

I want to check SQLite database table record . Whether table row is exist then update or delete my table row or.When I run my app the table row insert duplicate.How to avoid it . I want to insert newly record when I run first time , when open the activity second time my database is update. I have tried but db is not show record there.Please help me.Thanks to appreciates
Here is my code
public boolean Exists(String _id)
{
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery("select Company_Id from Company where Company_Id = ?",
new String[]{_id});
boolean exists = (cursor.getCount() > 0);
cursor.close();
return exists;
}
My fragment code
if(jsonStr != null)
try {
JSONObject jsonObj = new JSONObject(jsonStr);
String jsonResult = jsonObj.toString().trim();
Log.e("jsonResult ", " = " + jsonResult);
JSONObject companyList = jsonObj.getJSONObject("Get_CompanyResult");
Log.e("companyList ", " = " + companyList.toString());
JSONArray jarr = companyList.getJSONArray("CompanylList");
Log.e("jarr ", " = " + jarr.toString());
for (int i = 0; i < jarr.length(); i++) {
JSONObject jobCompanyDetails = jarr.getJSONObject(i);
str_CompanyId = jobCompanyDetails.getString("Company_ID");
str_CompanyName = jobCompanyDetails.getString("Company_Name");
Log.e("str_CompanyId ", " = " + str_CompanyId);
Log.e("str_CompanyName ", " = " + str_CompanyName);
if(dbhelper.Exists(str_CompanyId))
{
Log.e("Row is Already ","Exist");
}
else
{
dbhelper.insertCompany(str_CompanyId, str_CompanyName);
Log.e("Data insert into ", " Company Table Succesively !!! = ");
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
Use below method
public boolean isIDExist(String _id){
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(Company, new String[] { KEY_your_id}, KEY_your_id + "=?" ,
new String[] { String.valueOf( _id)}, null, null, null, null);
if (cursor != null){
if(cursor.getCount() == 0){
cursor.close();
db.close();
return false;
}else{
cursor.close();
db.close();
return true;
}
}
return false;
}
Change your code to this
public boolean Exists(String _id)
{
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery("select Company_Id from Company where Company_Id ='"+ String _id + "'", null);
boolean exists = (cursor.getCount() > 0);
cursor.close();
return true;
}
I think the simplest way to do this is to create a Primary Key in the table, and then use INSERT OR REPLACE command instead of just using INSERT.
INSERT OR REPLACE will automatically REPLACE the existing row when it encounters a Primary Key violation, with the new data being inserted.
In this case, you can have OrgId as the Primary Key and if you have some record like:
ORGID ORGNAME
1 ABC
and you insert like INSERT OR REPLACE INTO ORG_MASTER(1,'EFG'), the table will now have one row like
ORGID ORGNAME
1 EFG
Hope this helps :)

Java - jTable sort numbers

I have searched for very long time so I have decided to write finally here. I have problem with sorting numbers (Integers, doubles, shorts) in a jTable, I have overwritten the getColumnClass method, however it still does not sort numbers correctly.
Here is what I did:
List<Class> types = new ArrayList();
types.add(String.class);
types.add(String.class);
types.add(String.class);
for (int s = 0; s < sloupce.size(); s++) {
try {
Statement st = log.getSt();
ResultSet r = st.executeQuery("SELECT DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = '" + table + "' AND COLUMN_NAME = '" + sloupce.get(s) + "'");
if (r.next()) {
String typ = r.getString("DATA_TYPE");
if (!typ.equals("varchar")) {
types.add(Integer.class);
} else {
types.add(String.class);
}
}
} catch (Exception e) { System.out.println(e.toString()); }
}
DefaultTableModel tm = new DefaultTableModel(new Object[0][], new String[] {" first column ", " second ", " another "}) {
#Override
public Class getColumnClass(int columnIndex) {
return types.get(columnIndex);
}
};
Then I fill types array withproper classes, when I test the getColumnClass method it really returns proper class (java.lang.Integer), but it still sorts the values incorrectly.
//UPDATE:
I am representing a table from MySQL DB so I have updated my exact code how I am doing it.

check whether the data is already exist in table, or to check table is empty

friends,
I need help in sqlite query for check whether the data is already exist in table,
or to check table is empty or not,let's give queries for it.
Thanks in advance.
REFINED QUERY
SELECT COUNT(*) FROM TABLE WHERE
ROWNUM=1
SELECT COUNT(*) FROM `tableName`;
if the result is 0 the table is empty ;)
Also please kindly read about DatabaseUtils.
/**
* checks database if a column has a value in the table
*
* #param db
* #param tableName
* #param column
* #param value
* #param rowid to check against and skip if necessary
* #return boolean
*/
public static boolean ExistsWithName(SQLiteDatabase db, String tableName, String column,
String value, Long rowid) {
String sql = String.format("select 1 from %s where %s = '%s'", tableName, column, value);
if (rowid != null) {
sql += " and _id != " + rowid;
}
Cursor c = null;
Boolean ret = false;
try {
c = db.rawQuery(sql, null);
if (c != null) {
if (c.moveToFirst()) {
ret = (c.getCount() > 0);
} else {
ret = false;
}
}
} catch (Exception e) {
Log.v(tableName, e.getMessage(), e);
e.printStackTrace();
} finally {
if (c != null)
c.close();
}
return ret;
}
Try this,
public int getTableCount(String tableName) {
int totalCount= 0;
Cursor cur = mDb.rawQuery("SELECT COUNT(*) as count FROM " + tableName , null);
if (cur != null) {
cur.moveToFirst();
}
if (cur.moveToFirst()){
do{
totalCount = cur.getInt(cur.getColumnIndex("count"));
}while(cur.moveToNext());
}
cur.close();
return totalCount;
}
where "mDb" --> SQLiteDatabase object

Categories