Does anyone know if it is possible to sum a column using Sugar ORM? I've tried to find any documentation, and there is a raw query method, however, the raw query method does not have any returning values.
Example: "select sum(price) from atable"
Class.executeQuery() is void.
Sugar ORM does not seem very usable until this kind of features (along with JOIN etc) are present.
I finally do it with the following code:
long sumValue = -1L;
Database db = ((Application)SugarApp.getSugarContext()).obtainDatabase();
SQLiteDatabase sqLiteDatabase = db.getDB();
SQLiteStatement sqLiteStatement = sqLiteDatabase.compileStatement(
"SELECT SUM(column_name) FROM table_name");
try {
sumValue = sqLiteStatement.simpleQueryForLong();
} catch (Exception var16) {
var16.printStackTrace();
} finally {
sqLiteStatement.close();
}
Also need to change the Application class to can access to the DataBase property because has protected access (don't forget to modify the manifest properly).
public class Application extends SugarApp {
public Database obtainDatabase(){
return getDatabase();
}
}
Hope it helps.
You can perform raw queries by accessing sugar database object by reflection:
int sumValue = -1;
Field f = null;
try {
f = SugarContext.getSugarContext().getClass().getDeclaredField("sugarDb");
f.setAccessible(true);
SugarDb db = (SugarDb) f.get(SugarContext.getSugarContext());
Cursor cursor = db.getDB().
rawQuery("Select Sum(COLUMN_NAME) as s from TABLE_NAME" , null);
if (cursor.moveToFirst())
sumValue = cursor.getInt(cursor.getColumnIndex("s"));
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
It does not seem possible at present time. I ended up using greenDAO instead, a much faster (not depending on reflection) solution which gives access to the SQLiteDatabase-object, enabling all kind of custom possibilities.
The answer might be too late, but it will help new comers, its pretty easy to query custom queries to the database in order to SUM or use any query you could obtain access to the Database by the following code:
SugarDb sugarDb = new SugarDb(context);
then its pretty straight forward to query the database for example you could do
SQLiteDatabase database = sugarDb.getDB();
SQLiteStatement query = database.compileStatement("SELECT SUM(AMOUNT) FROM EXPENSES_MODEL");
try {
total = query.simpleQueryForLong();
} catch (Exception e) {
e.printStackTrace();
} finally {
query.close();
}
notice the underscore in table name? its how Sugar ORM names our tables so please be careful when calling the table.
notice how the column name is capitalised? its because Sugar ORM capitalise each column.
Related
I'm creating a forum application and I currently if I delete a thread I'm deleting all threads.
Is there a good method or query to check if the UserId == ThreadId?
My current code:
public void deleteThread() {
SQLiteDatabase db = this.getWritableDatabase();
// Delete All Rows
db.delete(TABLE_THREAD, null, null);
db.close();
Log.d(TAG, "Deleted all Thread info from sqlite");
}
You need to pass correct value to the well-documented delete method to narrow down the scope of deletion to a subset of all entries in the DB table.
public void deleteThreadById(String threadId) {
SQLiteDatabase db = this.getWritableDatabase();
String whereClause = "threadId = " + threadId;
db.delete(TABLE_THREAD, whereClause, null);
db.close();
}
Deleting all threads of a given user via their userId would be similar but probably doesn't make sense in a forum software.
This is how SQL works in general and it's a bit scary you started development without familiarising yourself with the very basics.
Something like this;
public void deleteThread(String threadName) {
SQLiteDatabase db = this.getWritableDatabase();
try {
db.delete(MYDATABASE_TABLE, "name = ?", new String[]{threadName});
} catch (Exception e) {
e.printStackTrace();
} finally {
db.close();
}
}
Something long these lines, querying database to find the specific row that has column which matches the parameter.
For example to delete a row which the name column is "Hello World";
deleteThread("Hello World");
I need to parse a fairly large XML file (varying between about a hundred kilobytes and several hundred kilobytes), which I'm doing using Xml#parse(String, ContentHandler). I'm currently testing this with a 152KB file.
During parsing, I also insert the data in an SQLite database using calls similar to the following: getWritableDatabase().insert(TABLE_NAME, "_id", values). All of this together takes about 80 seconds for the 152KB test file (which comes down to inserting roughly 200 rows).
When I comment out all insert statements (but leave in everything else, such as creating ContentValues etc.) the same file takes only 23 seconds.
Is it normal for the database operations to have such a big overhead? Can I do anything about that?
You should do batch inserts.
Pseudocode:
db.beginTransaction();
for (entry : listOfEntries) {
db.insert(entry);
}
db.setTransactionSuccessful();
db.endTransaction();
That increased the speed of inserts in my apps extremely.
Update:
#Yuku provided a very interesting blog post: Android using inserthelper for faster insertions into sqlite database
Since the InsertHelper mentioned by Yuku and Brett is deprecated now (API level 17), it seems the right alternative recommended by Google is using SQLiteStatement.
I used the database insert method like this:
database.insert(table, null, values);
After I also experienced some serious performance issues, the following code speeded my 500 inserts up from 14.5 sec to only 270 ms, amazing!
Here is how I used SQLiteStatement:
private void insertTestData() {
String sql = "insert into producttable (name, description, price, stock_available) values (?, ?, ?, ?);";
dbHandler.getWritableDatabase();
database.beginTransaction();
SQLiteStatement stmt = database.compileStatement(sql);
for (int i = 0; i < NUMBER_OF_ROWS; i++) {
//generate some values
stmt.bindString(1, randomName);
stmt.bindString(2, randomDescription);
stmt.bindDouble(3, randomPrice);
stmt.bindLong(4, randomNumber);
long entryID = stmt.executeInsert();
stmt.clearBindings();
}
database.setTransactionSuccessful();
database.endTransaction();
dbHandler.close();
}
Compiling the sql insert statement helps speed things up. It can also require more effort to shore everything up and prevent possible injection since it's now all on your shoulders.
Another approach which can also speed things up is the under-documented android.database.DatabaseUtils.InsertHelper class. My understanding is that it actually wraps compiled insert statements. Going from non-compiled transacted inserts to compiled transacted inserts was about a 3x gain in speed (2ms per insert to .6ms per insert) for my large (200K+ entries) but simple SQLite inserts.
Sample code:
SQLiteDatabse db = getWriteableDatabase();
//use the db you would normally use for db.insert, and the "table_name"
//is the same one you would use in db.insert()
InsertHelper iHelp = new InsertHelper(db, "table_name");
//Get the indices you need to bind data to
//Similar to Cursor.getColumnIndex("col_name");
int first_index = iHelp.getColumnIndex("first");
int last_index = iHelp.getColumnIndex("last");
try
{
db.beginTransaction();
for(int i=0 ; i<num_things ; ++i)
{
//need to tell the helper you are inserting (rather than replacing)
iHelp.prepareForInsert();
//do the equivalent of ContentValues.put("field","value") here
iHelp.bind(first_index, thing_1);
iHelp.bind(last_index, thing_2);
//the db.insert() equilvalent
iHelp.execute();
}
db.setTransactionSuccessful();
}
finally
{
db.endTransaction();
}
db.close();
If the table has an index on it, consider dropping it prior to inserting the records and then adding it back after you've commited your records.
If using a ContentProvider:
#Override
public int bulkInsert(Uri uri, ContentValues[] bulkinsertvalues) {
int QueryType = sUriMatcher.match(uri);
int returnValue=0;
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
switch (QueryType) {
case SOME_URI_IM_LOOKING_FOR: //replace this with your real URI
db.beginTransaction();
for (int i = 0; i < bulkinsertvalues.length; i++) {
//get an individual result from the array of ContentValues
ContentValues values = bulkinsertvalues[i];
//insert this record into the local SQLite database using a private function you create, "insertIndividualRecord" (replace with a better function name)
insertIndividualRecord(uri, values);
}
db.setTransactionSuccessful();
db.endTransaction();
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
return returnValue;
}
Then the private function to perform the insert (still inside your content provider):
private Uri insertIndividualRecord(Uri uri, ContentValues values){
//see content provider documentation if this is confusing
if (sUriMatcher.match(uri) != THE_CONSTANT_IM_LOOKING_FOR) {
throw new IllegalArgumentException("Unknown URI " + uri);
}
//example validation if you have a field called "name" in your database
if (values.containsKey(YOUR_CONSTANT_FOR_NAME) == false) {
values.put(YOUR_CONSTANT_FOR_NAME, "");
}
//******add all your other validations
//**********
//time to insert records into your local SQLite database
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
long rowId = db.insert(YOUR_TABLE_NAME, null, values);
if (rowId > 0) {
Uri myUri = ContentUris.withAppendedId(MY_INSERT_URI, rowId);
getContext().getContentResolver().notifyChange(myUri, null);
return myUri;
}
throw new SQLException("Failed to insert row into " + uri);
}
I'm trying to build my first Android application, but I'm experiencing a problem: I write following code for insert record in database, but I don't know how to delete a row, so can anybody help me???
Code for insert record:
public void btnAddEmp_Click(View view)
{
boolean ok=true;
try
{
Spannable spn=txtAge.getText();
String name=txtName.getText().toString();
int age=Integer.valueOf(spn.toString());
int deptID=Integer.valueOf((int)spinDept.getSelectedItemId());
Student emp=new Student(name,age,deptID);
dbHelper.AddEmployee(emp);
}
catch(Exception ex)
{
ok=false;
CatchError(ex.toString());
}
finally
{
if(ok)
{
//NotifyEmpAdded();
Alerts.ShowEmpAddedAlert(this);
txtEmps.setText("Number of students "+String.valueOf(dbHelper.getEmployeeCount()));
}
}
}
DELETE FROM tableName WHERE fieldName = value
This is delete query. Execute it with execSql
Edit: use execSql instead of rawQuery
You can simply do this using SQLiteDatabase.execSQL() and don't try rawQuery It's meant for querying.
SQLiteDatabase db = this.getWritableDatabase();
db.execSQL("DELETE FROM tableName where fieldName=Value");
db.close();
Check out the detailed answer here
I would like to delete a record in the database with multiple WHERE arguments.
My database helper class has this method:
public void deleteManualRow(String where){
try {db.delete(TABLE_NAME_MANUAL, where, null);}
catch (Exception e)
{
Log.e("DB ERROR", e.toString());
e.printStackTrace();
}
}
The "where" string which is passed to this method is seen as this through the debugger:
eventName='Manual Event 6' AND eventStartTime='2011-07-18T05:40:00.000-0400' AND eventEndTime='2011-07-18T06:40:00.000-0400'
How am I supposed to structure this WHERE clause if I want to delete a record with multiple arguments for WHERE? All of the datatypes are strings.
like this db.delete(TABLE_NAME_MANUAL,"Column1='5' and column2 like '3'", null);
You have to learn your sqlite api, next I show from Android flutter example.
From sqlite_api.dart:
Future<int> delete(String table, {String where, List<dynamic> whereArgs});
So your result code will be:
await db.delete(tableName, where: 'place_id = ? and country_id = ?', whereArgs: [place_id, country_id]);
I need to parse a fairly large XML file (varying between about a hundred kilobytes and several hundred kilobytes), which I'm doing using Xml#parse(String, ContentHandler). I'm currently testing this with a 152KB file.
During parsing, I also insert the data in an SQLite database using calls similar to the following: getWritableDatabase().insert(TABLE_NAME, "_id", values). All of this together takes about 80 seconds for the 152KB test file (which comes down to inserting roughly 200 rows).
When I comment out all insert statements (but leave in everything else, such as creating ContentValues etc.) the same file takes only 23 seconds.
Is it normal for the database operations to have such a big overhead? Can I do anything about that?
You should do batch inserts.
Pseudocode:
db.beginTransaction();
for (entry : listOfEntries) {
db.insert(entry);
}
db.setTransactionSuccessful();
db.endTransaction();
That increased the speed of inserts in my apps extremely.
Update:
#Yuku provided a very interesting blog post: Android using inserthelper for faster insertions into sqlite database
Since the InsertHelper mentioned by Yuku and Brett is deprecated now (API level 17), it seems the right alternative recommended by Google is using SQLiteStatement.
I used the database insert method like this:
database.insert(table, null, values);
After I also experienced some serious performance issues, the following code speeded my 500 inserts up from 14.5 sec to only 270 ms, amazing!
Here is how I used SQLiteStatement:
private void insertTestData() {
String sql = "insert into producttable (name, description, price, stock_available) values (?, ?, ?, ?);";
dbHandler.getWritableDatabase();
database.beginTransaction();
SQLiteStatement stmt = database.compileStatement(sql);
for (int i = 0; i < NUMBER_OF_ROWS; i++) {
//generate some values
stmt.bindString(1, randomName);
stmt.bindString(2, randomDescription);
stmt.bindDouble(3, randomPrice);
stmt.bindLong(4, randomNumber);
long entryID = stmt.executeInsert();
stmt.clearBindings();
}
database.setTransactionSuccessful();
database.endTransaction();
dbHandler.close();
}
Compiling the sql insert statement helps speed things up. It can also require more effort to shore everything up and prevent possible injection since it's now all on your shoulders.
Another approach which can also speed things up is the under-documented android.database.DatabaseUtils.InsertHelper class. My understanding is that it actually wraps compiled insert statements. Going from non-compiled transacted inserts to compiled transacted inserts was about a 3x gain in speed (2ms per insert to .6ms per insert) for my large (200K+ entries) but simple SQLite inserts.
Sample code:
SQLiteDatabse db = getWriteableDatabase();
//use the db you would normally use for db.insert, and the "table_name"
//is the same one you would use in db.insert()
InsertHelper iHelp = new InsertHelper(db, "table_name");
//Get the indices you need to bind data to
//Similar to Cursor.getColumnIndex("col_name");
int first_index = iHelp.getColumnIndex("first");
int last_index = iHelp.getColumnIndex("last");
try
{
db.beginTransaction();
for(int i=0 ; i<num_things ; ++i)
{
//need to tell the helper you are inserting (rather than replacing)
iHelp.prepareForInsert();
//do the equivalent of ContentValues.put("field","value") here
iHelp.bind(first_index, thing_1);
iHelp.bind(last_index, thing_2);
//the db.insert() equilvalent
iHelp.execute();
}
db.setTransactionSuccessful();
}
finally
{
db.endTransaction();
}
db.close();
If the table has an index on it, consider dropping it prior to inserting the records and then adding it back after you've commited your records.
If using a ContentProvider:
#Override
public int bulkInsert(Uri uri, ContentValues[] bulkinsertvalues) {
int QueryType = sUriMatcher.match(uri);
int returnValue=0;
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
switch (QueryType) {
case SOME_URI_IM_LOOKING_FOR: //replace this with your real URI
db.beginTransaction();
for (int i = 0; i < bulkinsertvalues.length; i++) {
//get an individual result from the array of ContentValues
ContentValues values = bulkinsertvalues[i];
//insert this record into the local SQLite database using a private function you create, "insertIndividualRecord" (replace with a better function name)
insertIndividualRecord(uri, values);
}
db.setTransactionSuccessful();
db.endTransaction();
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
return returnValue;
}
Then the private function to perform the insert (still inside your content provider):
private Uri insertIndividualRecord(Uri uri, ContentValues values){
//see content provider documentation if this is confusing
if (sUriMatcher.match(uri) != THE_CONSTANT_IM_LOOKING_FOR) {
throw new IllegalArgumentException("Unknown URI " + uri);
}
//example validation if you have a field called "name" in your database
if (values.containsKey(YOUR_CONSTANT_FOR_NAME) == false) {
values.put(YOUR_CONSTANT_FOR_NAME, "");
}
//******add all your other validations
//**********
//time to insert records into your local SQLite database
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
long rowId = db.insert(YOUR_TABLE_NAME, null, values);
if (rowId > 0) {
Uri myUri = ContentUris.withAppendedId(MY_INSERT_URI, rowId);
getContext().getContentResolver().notifyChange(myUri, null);
return myUri;
}
throw new SQLException("Failed to insert row into " + uri);
}