Efficient batch SQL query execution on Android, for upgrade database - android

As we Android developers know, the SQLiteDatabase execSQL method can execute only one statement.
The doc says:
Execute a single SQL statement that is not a query. For example, CREATE TABLE, DELETE, INSERT, etc. Multiple statements separated by ;s are not supported.
I have to load in a batch of records, 1000 and counting.
How do I insert these efficiently?
And what's the easiest way to deliver these SQLs with your apk?
I mention, there is already a system database and I will run this on the onUpdate event.
I have this code so far:
List<String[]> li = new ArrayList<String[]>();
li.add(new String[] {
"-1", "Stop", "0"
});
li.add(new String[] {
"0", "Start", "0"
});
/* the rest of the assign */
try {
for (String[] elem : li) {
getDb().execSQL(
"INSERT INTO " + TABLENAME + " (" + _ID + "," + NAME + "," + PARSE_ORDER
+ ") VALUES (?,?,?)", elem);
}
} catch (Exception e) {
e.printStackTrace();
}

How do I insert these efficiently?
Use transaction:
db.beginTransaction();
try {
for(;;) {
db.execSQL(...);
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}

I think what you have is the only way to load those 1000 records, now, as far as deploying that DB with your apk file, check out this post:
http://www.helloandroid.com/tutorials/how-have-default-database

Related

Android - SQLiteException while deleting record

Currently We have one application in which we are receiving many crash reports while deleting record from database .
Here is method in which app is crashing.
public int deleteGroupMap(String nickName) {
SQLiteDatabase database = this.getWritableDatabase();
try {
return database.delete(TABLE_NAME_GROUP_MAP, COLUMN_GMAP_NICK_NAME + " = '" + nickName + "'", null);
} catch (Exception e) {
e.printStackTrace();
} finally {
database.close();
}
return 0;
}
but we am getting following exception:
android.database.sqlite.SQLiteException: near "adz": syntax error
(code 1): , while compiling: DELETE FROM groups_map WHERE
gmap_nick_name = ''adz.'
Any help will be appreciated.
Look at delete signature:
int delete (String table, String whereClause, String[] whereArgs)
Third argument is where args:
You may include ?s in the where clause, which will be replaced by the
values from whereArgs. The values will be bound as Strings.
It's automatically escaped, so there is no need to put quotes (', ") manually.
Use where args instead of strings concating:
database.delete(TABLE_NAME_GROUP_MAP, COLUMN_GMAP_NICK_NAME + " = ?", new String[] { nickName });
Try Like This
public int deleteGroupMap(String nickName) {
SQLiteDatabase database = this.getWritableDatabase();
try {
database .execSQL("DELETE FROM "+ TABLE_NAME_GROUP_MAP + " WHERE " + COLUMN_GMAP_NICK_NAME + " = "+nickName+"");
database .close();
} catch (Exception e) {
e.printStackTrace();
} finally {
database.close();
}
return 0;
}
Try this
return database.delete(TABLE_NAME_GROUP_MAP, COLUMN_GMAP_NICK_NAME + "= ?" , new String[]{Long.toString(nickName)});
You should also use parameter markers because appending values directly is error prone when the source contains special characters.
try following because it will also prevent SQL injections to your app
database.delete(TABLE_NAME_GROUP_MAP, COLUMN_GMAP_NICK_NAME + "=?", new String[]{String.valueOf(nickName));

Android sqlite update not done in table

Following is my code for update record done.
try {
String str_edit = edit_note.getText().toString();
Toast.makeText(getApplicationContext(), str_edit,
Toast.LENGTH_LONG).show();
Toast.LENGTH_LONG).show();
String rawQuery="UPDATE " + GlobalVariable.getstr_tbl_name()
+ " SET note = '" + str_edit + "' where name = '"
+ str + "' ";
db.execSQL(rawQuery);
} catch (Exception e) {
System.out.println(e.getMessage());
}
Code for Display:
try {
Cursor note_cursor = db.query(GlobalVariable.getstr_tbl_name(),
new String[] { "note" + " as note" }, "name" + "=?",
new String[] { GlobalVariable.getstr_food_name() }, null,
null, null);
if (note_cursor.moveToFirst()) {
int notecol = note_cursor.getColumnIndex("note");
do {
String str = note_cursor.getString(notecol);
Toast.makeText(getApplicationContext(), str,
Toast.LENGTH_LONG).show();
edit_note.setText(str);
} while (note_cursor.moveToNext());
}
}
catch (Exception e) {
System.out.println(e.getMessage());
}
I am getting all variable value i.e global variables and all but update does not reflects on table.
What wrong i am done?
whenever we try to update our database then just clean and uninstall your app then again install may be some changes not take place when we don't uninstall it if u find correct then tell other wise we will see the next
Should
int notecol = note_cursor.getColumnIndex("name");
instead be
int notecol = note_cursor.getColumnIndex("note");
since in the first block of code you are updating note..
The problem is that you try to update your DB using a rawQuery method instead of a execSql. RawQuery is intended to retrieve data from your database, while execSql lets you
Execute a single SQL statement that is NOT a SELECT or any other SQL statement that returns data.
You can also consider to use public int update (String table, ContentValues values, String whereClause, String[] whereArgs) method.

Bulk Update Database

I've been looking on this site for a while but have not found the answer. I am trying to do a bulk update on data that I know is already in the table. I have one column that needs to be set when a certain condition comes back for the row ID. Here is the single method but I want to make this more efficient and do it as a bulk. Our database is not in a Provider so I just using a Helper class.
public void markUnavailable(int myId) {
SQLiteDatabase db = this.getWritableDatabase();
String sql = "UPDATE " + MYTABLE + " SET " + Col.IS_AVAILABLE + "= 0"+ " WHERE " + Col.MY_ID + "=" + myId;
db.execSQL(sql);
db.close();
}
I would like to pass in an array of myIds to do the bulk Update. I can't do a Insert or Replace statement because I don't have access to all the column data and don't want to pass this through due to too many codes changes.
public void markUnavailable(int[] myId) {
// ????
/// need some way to loop through and update in bulk
}
Try UPDATE tablename SET column=0 WHERE ID IN (...), where ... is a comma-delimited list of ID values.
I'm not an Android developer, but according to good database practices, you should:
public void markUnavailable(int[] myId) {
SQLiteDatabase db = this.getWritableDatabase();
db.beginTransaction();
SQLiteStatement upd=db.compileStatement("UPDATE "+MYTABLE+" SET "+Col.IS_AVAILABLE+"=0 WHERE "+Col.MY_ID+"=?";
for (int i = 0; i < myId.length; i++) {
upd.bindLong(1, myId[i]);
upd.execute();
}
db.endTransaction();
}
Android has SQLiteDatabase.update would be very usefull in this case, but String [] whereArgs would not deal well with your int[] myId.
The fastest way to do a bulk update would be to do it as a single transaction,by using begin and end transactions. Also if the size of the database is large it will be a good idea to make myID as the primary key of the table as it will significantly increase the speed of the speed in fetching the rows for update when the WHERE clause is used.[It is said that indexing can reduce the speed of update and insert but when the where clause is used,indexing has always increased my speed by huge margins.
public void markUnavailable(int[] myId) {
SQLiteDatabase db = this.getWritableDatabase();
db.beginTransaction();
SQLiteStatement upd=db.compileStatement("UPDATE "+MYTABLE+" SET "+Col.IS_AVAILABLE+"=0 WHERE "+Col.MY_ID+"=?");
for (int i = 0; i < myId.length; i++) {
upd.clearBindings();
upd.bindLong(1, myId[i]); // this matches the first "?"
upd.execute();
}
db.setTransactionSucessful();
db.endTransaction();
}

Error on using REPLACE character manipulation function on query SQLite Android

it gives me an error when I am using this key but when I use LENGTH, it works fine. I hope it is allowed on android sqlite coz it's the best way for this:
I am just trying to remove the spaces after words that will be selected from Database.
public ArrayList<String> getCorrectList() {
// TODO Auto-generated method stub
Cursor c = db.rawQuery("SELECT REPLACE(Level_1, ' ', '') FROM " + TABLE, null);
ArrayList<String> resultsList = new ArrayList<String>();
try {
if (c != null) {
if (c.moveToFirst()) {
do {
String levelData = c.getString(c
.getColumnIndex("Level_1"));
resultsList.add("" + c.getColumnIndex("Level_1"));
} while (c.moveToNext());
}
}
} catch (SQLiteException e) {
Log.e("Database", "Cannot get List (" + e + ")");
}
Log.d("array", "List: " + resultsList);
Collections.shuffle(resultsList);
return resultsList;
}
This works fine in SQLite3 shell:
e$ sqlite3
SQLite version 3.7.14.1 2012-10-04 19:37:12
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> create table t(a,b,c);
sqlite> select replace(a,' ', '') from t;
REPLACE is both a function and a command in SQLite3. Perhaps db.rawQuery is parsing the query and getting confused by REPLACE. Try this:
db.rawQuery("select rtrim(replace(Level_1, ' ', '')) FROM " + TABLE, null);

Most efficient way to access/write data to SQLite on Android

Currently I'm using ContentProvider in my application. Because of "layers" and no actual need for provider - I'm working on optimizing data access as much as possible. Here is my attempt to do this:
public static String getPreferenceString(Context context, String key)
{
DatabaseHelper helper = new DatabaseHelper(context);
SQLiteDatabase database = helper.getReadableDatabase();
SQLiteStatement statement = database.compileStatement("SELECT Value FROM Preferences WHERE Key='" + key + "' LIMIT 1");
try
{
return statement.simpleQueryForString();
}
catch (Exception ex)
{
return "";
}
finally
{
statement.close();
database.close();
helper.close();
}
}
public static void setPreferenceString(Context context, String key, String value)
{
DatabaseHelper helper = new DatabaseHelper(context);
SQLiteDatabase database = helper.getReadableDatabase();
SQLiteStatement statement = database.compileStatement("INSERT OR REPLACE INTO Preferences (Key, UpdatedOn, Value) VALUES ('" +
key + "', '" +
Utility.getDateConvertedToUTCDBString(new Date()) + "', '" +
value + "'); ");
try
{
statement.execute();
}
finally
{
statement.close();
database.close();
helper.close();
}
}
Is that about as close as I can get to direct calls to SQLite?
Should I have all this .close() statements in my code?
In setPreferenceString I did copy/paste and called getReadableDatabase even though I write data and it works. Why?
Is that about as close as I can get to direct calls to SQLite?
AFAIK SQL queries are closest you can go against RDBs
Should I have all this .close() statements in my code?
Personally, I would not create a DatabaseHelper, an SQLiteDatabase, and an SQLiteStatement each time I call that method. I would create all this just before you need them, and close them when no needed anymore. Also centralizing this is a good idea IMHO (using a singleton, for example).
Also your SQL statement could be written like
SELECT Value FROM Preferences WHERE Key= ? LIMIT 1
This way you only have to prepare it once and bind parameters as you need the statement. Same goes for any SQL query.

Categories

Resources