Android SQLite Incrementing Integer Field Read from Query - android

Disclosure up front, this is a school project.
I have a method in a class that manages the database for a "quzzer" feature in my app, it is intended to increment (or decrement in one case) three integer fields in an SQLite database. It needs to do this independently from the "quizzing functions", so I need to pull the data first, change it, then update it into the database.
The fields are as follows in the database:
"prof_level" - Only acceptable values are 1 to 4 inclusive.
"times_correct" - Only positive numbers.
"times_incorrect" - Only positive numbers.
I can pull the numbers fine from the db then increment them by 1, but when I update, they increment the values in the db by 2 instead, and I've no idea why. Here is the full code of the method:
public void updateCharacterProf(String table, String charToUpdate, boolean isIncreased){
//get character from table
SQLiteDatabase db = getReadableDatabase();
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables(table);
String[] projection = {"prof_level", "times_correct", "times_incorrect"};
Cursor c = qb.query(db, projection, "character=='" + charToUpdate + "'", null, null, null,
null, null);
c.moveToFirst();
//check to see if the prof level is at max/min
int profLevel = c.getInt(0);
int correctTimes = c.getInt(1);
int incorrectTimes = c.getInt(2);
//mod prof levels
if (isIncreased){
profLevel++;
correctTimes++;
}
else{
profLevel--;
incorrectTimes++;
}
if (profLevel == 4 && isIncreased){
profLevel = 4;
}
else if (profLevel == 1 && !isIncreased){
profLevel = 1;
}
c.close();
ContentValues values = new ContentValues();
values.put("prof_level", profLevel);
values.put("times_correct", correctTimes);
values.put("times_incorrect", incorrectTimes);
//update db
db.update(table, values, "character=='" + charToUpdate + "'", null);
db.close();
}
I'm hoping that it's just something I don't get about how updating SQLite dbs, but I'm lost at the "var++ == +=2" thing that I'm getting now.

I discovered that the issue was o e of my own creation, I fired the callback that calls this database update twice accidently in the dialog fragment that calls it (once in an onClick method and once in a life cycle onDismiss override.).
Fixing this bug, which happened during another different dateabase related thing, fixed the problem for me.

Related

Returning sqlite query as cursor or object/list

When I started my app years ago, I did some tutorials and always did my queries to the database returning the cursor (without closing it):
public Cursor querySingleId(String szId) {
SQLiteDatabase db = getWritableDatabase();
return db.query(TABLE_ADR, szGetTableEntries, _ID + " = ?", new String[]{szId}, null, null, null);
}
Now I am refactoring my code to MVVM and added models, so I changed my code to this:
public Card querySingleId(String szId) {
SQLiteDatabase db = getWritableDatabase();
Cursor c1 = db.query(TABLE_ADR, szGetTableEntries, _ID + " = ?", new String[]{szId}, null, null, null);
c1.moveToFirst();
return new Card(c1.getString(c1.getColumnIndex(DbHandler.NAME)),
c1.getString(c1.getColumnIndex(DbHandler.STREET)),
c1.getString(c1.getColumnIndex(DbHandler.CITY)));
}
I read that cursors should always be closed (memory leak). Which is the best/most conform approach to return my data from the database? I'm also unsure if there are multiple results, should I stay with a cursor or change to a list?
public List<Card> queryAll() {
SQLiteDatabase db = getWritableDatabase();
Cursor c1 = db.query(TABLE_ADR, szGetTableEntries, null, null, null, null, null);
List<Card> list = new ArrayList<>();
if(c1.moveToFirst()){
do{
list.add(new Card(c1.getString(c1.getColumnIndex(DbHandler.NAME)),
c1.getString(c1.getColumnIndex(DbHandler.STREET)),
c1.getString(c1.getColumnIndex(DbHandler.CITY))));
} while(c1.moveToNext());
}
c1.close();
return list;
}
Is this all just a matter of taste or are there reasons why it should return a cursor or a list/object? Depending where in my code I need the data, a list or a cursor is more convenient.
I'm just not sure what is the correct approach in sqlite queries. There are so many code examples and but it seems most is copy/paste without really digging into the topic.
If the query can return multiple rows then you should return a list.
If you are sure that the query will return just a single Card then returning that single Card would be OK (probably preferable) BUT you should close the Cursor.
However, there isn't an actual requirement/need to do so (e.g. if you your initial activity uses a Cursor for a ListView/Spinner then you may not want to close the Cursor but reuse it and use the adapter's swapCursor when the Activity resumes). The cursor would be effectively closed, as would the database when the App finishes.
As you have used the column _ID which is typically used for a column that is an alias of the rowid column, which is typically generated by SQLite then if used/defined as such (column has been defined explicitly or implicitly as INTEGER PRIMARY KEY with or without AUTOINCREMENT) then it will be a unique value and only return a single row as you have _ID = ?. As such there is a high likeliehood that a single row, or no row would be returned, and unlikely that multiple rows are returned.
So (for a single Card):-
public Card querySingleId(String szId) {
SQLiteDatabase db = getWritableDatabase();
Cursor c1 = db.query(TABLE_ADR, szGetTableEntries, _ID + " = ?", new String[]{szId}, null, null, null);
c1.moveToFirst();
return new Card(c1.getString(c1.getColumnIndex(DbHandler.NAME)),
c1.getString(c1.getColumnIndex(DbHandler.STREET)),
c1.getString(c1.getColumnIndex(DbHandler.CITY)));
}
Should be something like :-
public Card querySingleId(String szId) {
SQLiteDatabase db = getWritableDatabase();
Card rv = null;
Cursor c1 = db.query(TABLE_ADR, szGetTableEntries, _ID + " = ?", new String[]{szId}, null, null, null);
if (c1.moveToFirst()) { //<<<<<< Should always check if the move moved
rv = new Card(c1.getString(c1.getColumnIndex(DbHandler.NAME)),
c1.getString(c1.getColumnIndex(DbHandler.STREET)),
c1.getString(c1.getColumnIndex(DbHandler.CITY)));
}
c1.close();
return rv; //<<<<< Note should check the returned Card for null
}
In addition to memory leaks not closing Cursors can result in a too many open connections (1K (1024) if memory serves correctly) and then a exception: unable to open database file (code 14); as underneath all the wrappers a Cursor has a file associated with it.

SQLiteDatabase delete(table_name, null, null) is not deleting all rows in the table

This is my code :
Db.getInstance().beginTransaction();
int i = Db.getInstance().delete("friends", null, null);
Log.e(TAG, "dropDB: " + i);
Db.getInstance().setTransactionSuccessful();
Db.getInstance().endTransaction();
I have searched the SO community, but cannot find what is wrong in this code. When I delete , the value of i is number of rows deleted, but still the database keeps returning rows.
Db is my own helper class in which I initialise the SQLiteDatabase's object and get getWritableDatabase().
May be nothing, but try only calling getInstance() once and setting it to a variable.
I use this in a CustomDialog when the user clicks the btnYES to delete the table.
I know the table only ever has one record because it hold a password so try this
db = helper.getReadableDatabase();
String q = "SELECT * FROM masterPW";
Cursor cursor = db.rawQuery(q,null);
// Above query gets TABLE_PW data from Col_IDI
// TABLE_PW will only ever have one row of data
int rowID = 99;
if(cursor.moveToFirst()){
rowID = cursor.getInt(cursor.getColumnIndex(Col_IDI));
str = cursor.getString(cursor.getColumnIndex(Col_MPW));
}
cursor.close();
// Line of code below WORKS deletes entire TABLE <=====
// Not a recommended way to re-set the master password
// db.delete(TABLE_PW, null, null);

Most recent added record into database

How should i get most recent added record from database, where COL_2 should == param that I pass into it.
I can get all records where COL_2 is equal to param with this code, but I need only recent one
public Cursor getRowsLast(String param) {
SQLiteDatabase db = helper.getWritableDatabase();
String[] COLS = new String[]{DatabaseHelper.COL_1,DatabaseHelper.COL_2, DatabaseHelper.COL_3,DatabaseHelper.COL_4};
String where = param;
Cursor c = db.query(true, DatabaseHelper.TABLE_NAME, COLS, DatabaseHelper.COL_2 + " = '" + where + "'", null, null, null, null, null);
if(c != null){
c.moveToFirst();
}
return c;
}
The most reliable way to get the most recent row in a table is to have a column defined in the table for the time of insert/update. Make sure this value is accurate at the time of insert/update, and create an index on it. You can then sort (descending) on this column to determine which one is the most recent - it will be the first row.
As the automatically generated ID values increase with every insert, the row with the highest ID will be the one that was inserted most recently. So add an 'order by _id desc' and the first row will be the most recently inserted one.
Note - this does not cover updates. If you need the row most recently inserted or updated, you'll have to use an additional timestamp column like Doug Stevenson suggested.

How do I add and subtract numbers in SQLite for android?

I'm creating a simple financial app where the user can input an income or expense. I cannot find anywhere how I can change the "total" amount by adding or subtracting numbers inside the database. The easiest way I can explain it is:
user enters an income of $10 : So I would add that 10 into the database.
user enters an expense of -$5 : so i would also add that into the database
the end result should be $5 as the total, but how do I do this?
I'm completely stuck as I've never use SQLite before. Thanks
You can do that simply by firing 2 commands on SQL
a) Use Select to get the value from the SQLite Database
b) In Android programming add them or subtract them
c) Update the new Total into the database
public void updateExpense(decimal Expense,String Condition) {
double current = 0;
db = this.getReadableDatabase();
String selectQuery = "select id, total from " + TABLE_YourTable ;
Cursor cursor = db.rawQuery(selectQuery, null);
int RowID=0;
if (cursor.moveToFirst()) {
current= Double.parseDouble(cursor.getString(1));
RowID= Integer.parseInt(cursor.getString(0));
}
/// Now we use condition --> if condition is positive it mean add ... if condition is negative it means
////subtract
if(Condition.equals("positive"){
current += Expense;
}else {
current =current - Expense;
}
cursor.close();
db.close();
//Your Update to SQLite
db = this.getReadableDatabase();
ContentValues values = new ContentValues();
values.put(total , current );
db.update(TABLE_YourTable , values, KEY_ID + " = ?", new String[] { String.valueOf(RowID) });
db.close();
}

Android SqlLite update last inserted row

This is what i am using for insert:
public long insert(String content, Date startAt, Date endAt) {
if (content == null || startAt == null) {
return 0;
}
ContentValues contentValues = new ContentValues();
contentValues.put(KEY_CONTENT, content);
contentValues.put(KEY_START_AT, startAt.getTime());
if (endAt == null) {
contentValues.putNull(KEY_END_AT);
} else {
contentValues.put(KEY_END_AT, endAt.getTime());
}
return sqLiteDatabase.insert(TABLE_NAME, null, contentValues);
}
now i want to create update method which will update last inserted row. How can i get last inserted row?
If you have an id attribute that works as a primary key, you can do a raw database query on SqlLite.
Cursor cc = this.mDb.rawQuery("SELECT *" + " FROM " + "<Your DATABASE_NAME> " +
"ORDER BY id " + "DESC LIMIT 1", null);
return cc;
Here,
1. It returns a cursor.
2. mDb is a SQLiteDatabase class instance.
3. ORDER BY id allows the query to sort by id number. As I said, if you have an id as primary key in your table, your latest entry will have the maximum id number.
4. DESC allows to sort by descending order.
5. LIMIT 1 allows to return only 1 row.
6. Always be careful when writing raw queries, white spaces inside the query can be a lot of pain when you do not handle them carefully.
For further queries you can see this tutorial. And obviously Divya's answer is also a good one.
You can use a cursor to retrieve rows and say :
cursor.moveToLast();
OR
cursor.moveToPosition(cursor.getCount() - 1);
When you insert a row in to your table the insert query returns the key of the last inserted row. You can now use this key to update this row.
for example
int newInsertedKey = sqLiteDatabase.insert(TABLE_NAME, null, contentValues);
update table_name set column_name = 'Change 2' where columnID = newInsertedKey
An efficient method would be to avoid anymore database queries to get the last updated row.
Maybe he should use something like this
public long getLastId() {
Cursor c = mDb.query(currentTableName, new String[] { "MAX(_id)" },
null, null, null, null, null, null);
try{
c.moveToFirst();
long id = c.getLong(0);
return id;
}catch(Exception e){
return 0;
}
}
where _id is column by which you identify rows

Categories

Resources