Android Cursor - Two floats not adding if they are equal? - java

This is a strange problem, and I hope it has a simple solution. I have a database with encrypted values. I have created a cursor that will go through each of the entries in a table, decrypt the value from the column I need, and add the value to a variable, "total". I want the sum of all of the values in the column. Here is the code:
while (c.moveToNext())
{
strTotal = c.getString(c.getColumnIndexOrThrow(KEY_TOTAL));
strTotal = sc.decrypt(strTotal);
total = Float.valueOf(strTotal) + total;
}
Now, here's the strange part. Let's suppose I have two values in the database: 2 + 4. After each is decrypted, it will correctly add them: 6. Now, if the values are equal: 2 + 2, for instance, the method returns "2" instead of "4". This happens even if it is off by a decimal (2 + 2.01 = 4.01, but 2 + 2 still outputs 2 for example).
Is there something I am missing here? Thanks!
EDIT:
I've changed the code around just to see if the decryption was the problem and it is still giving me the same result:
float total = 0;
String strTotal = "10";
while (c.moveToNext())
{
try {
//strTotal = sc.decrypt(c.getString(c.getColumnIndex(KEY_TOTAL)));
total = Float.valueOf(strTotal) + total;
} catch (Exception e) {
Log.e(TAG, "exception", e);
}
}
This code is returning "10", even though there are 3 entries in the database! It looks like if two rows in the database have the same value in the KEY_TOTAL field, it is returning less results. Here is the query:
Cursor c = mDb.query(true, DATABASE_TABLE, new String[] {KEY_TOTAL}, KEY_TYPE + "=" + t, null, null, null, null, null);
If I pull the db and open it with a sqlite browser, and SELECT all of the rows, I am getting 3 still, however.

I just checked the SQLite documentation for Android (I'm not an Android developer) and I think I found your problem. The first argument to the query method is whether to select distinct rows. Since you're passing TRUE and you're only selecting one column, duplicates will be removed from the result, which is not what you want.
Changing your call to query to the following should fix your issue.
Cursor c = mDb.query(false, DATABASE_TABLE, new String[] {KEY_TOTAL},
KEY_TYPE + "=" + t, null, null, null, null, null);

Have you checked for thrown exceptions? Especially NumberFormatException? I'm guessing there is some other logic problem that is causing the loop to exit prematurely.

Related

I'm trying to get sum of column in SQLite database

i want to get sum of column price but it show -2 in total price
//Dbhandler
public Cursor gettotalp()
{
SQLiteDatabase database = this.getReadableDatabase();
Cursor cursor =database.rawQuery("select sum(totalprice) as total from " + TABLE_Users + ";", null);
Log.d(TAG, "gettotalp: "+cursor.getCount());
return cursor;
}
//showallsaleitemActivity
Cursor cursor = db.gettotalp();
int m=0;
/* while (cursor.moveToNext()) {
m += cursor.getInt(cursor.getColumnIndex("totalprice"));
}*/
for(int k = 0; k<=cursor.getCount();k++) {
m += (int) Integer.parseInt(String.valueOf(cursor.getColumnIndex("totalprice")));
}
int i=m;
tp.setText("" + m);
database table image
Your primary issue is that the column name in the cursor does not match the column name passed to the getColumnIndex method.
Secondly the value you want is stored in the column of the Cursor, it is not the value of the index of the column in the Cursor. As it is the first and only column the index will be 0 and not the sum of the totalprice column. Instead you need to get the value stored in the column based upon the index of the column using one of the Cursor get???? methods in this case you want to use either getInt or getString (if you want to use the value for calculations then getInt means that you don't have to do the parseInt from a String, if you only want to display the value then getString could be used).
I personally prefer to get the value using the get method more appropriate to the type of value being retrieved. Hence as it's an integer value then I have used getInt even though it's being used as a string.
I would suggest the following 2 snippets of code be used :-
// DBHanlder
public int gettotalp() {
int rv = 0;
String total_column = "total_price";
SQLiteDatabase database = this.getReadableDatabase();
Cursor cursor =database.rawQuery("select sum(totalprice) as " + total_column + " from " + TABLE_Users + ";", null);
Log.d(TAG, "gettotalp: "+cursor.getCount());
if (cursor.moveToFirst()) {
rv = cursor.getInt(cursor.getColumnIndex(total_column));
}
cursor.close();
return rv;
}
chances of mistakes reduced by using a variable for the column name alias.
The Cursor moveToFirst method will move to the first row in the Cursor.
When a Cursor is returned from the SQLiteDatabase methods that create a Cursor the Cursor is at a position that is BEFORE the first row, so a move is required.
All the Cursor move???? methods return false if the move cannot be made.
A Cursor should always be closed when it is done with. Not doing so can lead to errors who's underlying cause (such as file handles exhausted) is difficult to determine.
2nd Snippet :-
//showallsaleitemActivity
tp.setText(Integer.toString(gettotalp()));
Note
Instead of using
cursor.getInt(cursor.getColumnIndex(total_column))
As you are only returning a single value you could use
cursor.getInt(0)
then the column name is then irrelevant (if valid for the SQL). Personally I prefer to not use hard coded index unless necessary or overly complex to not use them.
The column that returns the sum in your query is not totalprice.
You aliased it as total.
To get it, use this:
Cursor cursor = db.gettotalp();
cursor.moveToFirst()
int m = cursor.getInt(cursor.getColumnIndex("total"));
or, since the query returns only 1 column:
int m = cursor.getInt(0);
You don't need the for loop, which in your code adds twice -1 and returns -2 because cursor.getColumnIndex("totalprice") returns -1 (since the column does not exist).

Java & MySQL - Error with setBoolean() method

I'm getting the error: "Column count doesn't match value count at row 1", yet I have counted and I have the right number of columns and I feel that the error is with the setBoolean() method. I have 8 columns and you will see that I'm passing 7 arguments in my method as one of the columns is an AUTO_INCREMENTE. My coding works perfectly fine if I don't use the setBoolean method replacing it for a setString, setInt or whatever else, but not when I do it with setBoolean().
Here is my code, which I hope makes my problem clearer:
I have an automatic code in my Java that creates the Database & its respective table/s if it doesn't exist:
DB.createDB("userSecInfo");
DB.createTable("accountInfo", "userSecInfo", "("+
"Username VARCHAR(40) NOT NULL, "+
"Pass VARCHAR(40) NOT NULL, "+
"chkPwChange BOOLEAN NOT NULL DEFAULT FALSE, "+
"chkPwCntChange BOOLEAN NOT NULL DEFAULT FALSE, "+
"chkPwNoExpires BOOLEAN NOT NULL DEFAULT FALSE, "+
"chkPwExpires BOOLEAN NOT NULL DEFAULT FALSE, "+
"expirydays INT, "+
"UserID INT NOT NULL AUTO_INCREMENT, "+
"PRIMARY KEY (UserID))");
I have tried defining all the boolean variables for MySQL in different ways such as BOOL, also as BOOLEAN (as it's above) and as TINYINT & TINYINT(1); but the variable definition does not seem to be the problem.
Then the programme, once it has created the Database and the tables, it proceeds to extract the information that the user has inputted and inserts it into the Database:
DB.insertUserSecAccountInfo("userSecInfo", "accountInfo", tFUsername.getText(),
String.copyValueOf(pFPassword.getPassword()), chckbxUserMustChange.isSelected(),
chckbxUserCannotChange.isSelected(), chckbxPasswordNeverExpires.isSelected(),
chckbxPasswordExpiresAnd.isSelected(), Integer.parseInt(tFdays.getText()));
The insertUserSecAccountInfo method as below:
public void insertUserSecAccountInfo(String db_name,String table_name, String Username, String Pass,
boolean chkPwChange, boolean chkPwCntChange, boolean chkPwNoExpires,boolean chkPwExpires,
int expirydays) throws Exception {
try {
openConnection("whatever","password",db_name);
String Query ="INSERT into "+ table_name +" values(?,?,?,?,?,?,?)";
ps = Conexion.prepareStatement(Query);
ps.setString(1, Username);
ps.setString(2, Pass);
ps.setBoolean(3, chkPwChange);
ps.setBoolean(4, chkPwCntChange);
ps.setBoolean(5, chkPwNoExpires);
ps.setBoolean(6, chkPwExpires);
ps.setInt(7, expirydays);
ps.executeUpdate();
} catch (Exception ex) {
JOptionPane.showMessageDialog(null, "Error saving data"));
ex.printStackTrace();
} finally {
closeConnection();
}
}
When I run it, it shows me the error: "Column count doesn't match value count at row 1". But then I run basically the same line directly in MySQL as below, and it inserts it perfectly fine:
insert into accountInfo(Username,Pass,chkPwChange,chkPwCntChange,chkPwNoExpires,chkPwExpires,expirydays) values ('Hola','No',true,true,true,true,56);
So it makes me feel it's a problem with the setBoolean() method, which might not be mapping or passing correctly the boolean variables from Java to MySQL; has anyone had any similar issue? I would very much appreciate any guidance with this.
Thank you in advance.
Because you did not name every column explicitly, the implicit default of all columns applies. The fact that one of them has a default value is irrelevant (and autocounting is no more and no less than the script of: "Make a sequence, now set the default value for this column to NEXTVAL(nameOfGeneratedSequence)).
This has nothing whatsoever to do with setBoolean.
As some of the commenters have said, you need to always explicitly name the columns you're setting, so: `INSERT INTO " + tableName + " (Username, Pass, etc) VALUES (?,?,... etc)".
SECURITY NOTE: Storing passwords in plain text in a database does not fit with minimal security best practices. If deployed like this and it ever leaks out, you will likely receive a hefty fine or worse (In europe via the GDPR; other jurisdictions often have similar legislation), not to mention a heck of a lot of deserved media fallout. Do not do it this way. – use bcrypt and store the hash instead.

Issue with SQLiteDatabase.query() when SQLiteDatabase.rawQuery() works fine

I am having issue querying my SQLITE database in Android. I have a table called "resets" with some values in them. Currently I only have one entry.
reset_timestamp | interval
1479442048 | 5
This is the query I was trying to execute. However, it returns zero results when I call cursor.getCount(). The query I want to execute is:
SELECT reset_timestamp FROM resets WHERE (reset_timestamp=1479442048);
I don't really want to use rawQuery(). I want to use query(). Here is my query statement.
SQLiteDatabase db = new PowerDbHelper(this).getWritableDatabase();
String[] resetsQueryColumns = {"reset_timestamp"};
String[] resetsQuerySelectArgs = {"1479442048"};
Cursor cursor = db.query("resets", resetsQueryColumns, "reset_timestamp=?",
resetsQuerySelectArgs, null, null, null);
However, getCount() returns 0 with this. On the other hand, this works fine and returns my result
cursor = db.rawQuery("select reset_timestamp from resets where (reset_timestamp=1479442048)", null);
and getCount() returns 1, what I want. Putting quotes around '?' gives me
java.lang.IllegalArgumentException: Cannot bind argument at index 1 because the index is out of range
What am I doing wrong with query()?
"1479442048" is a string (you even wrote String in front of it). A string and a number are not equal.
The query function supports only string parameters, so you have to convert the string back into a number:
query(..., "reset_timestamp=CAST(? AS INT)", ...);
Alternatively, insert the number directly into the query:
query(..., "reset_timestamp=1479442048", null, ...);

Cursor isn't moving to first?

so I've build a method that return an ArrayList of a class that I use on my project, the problem is that the only item that is being add to the ArrayList is the 2nd on the database. I know that because I extracted the DB File and browsed it, and also the 'c.getCount()' return a value of 2.
So I know for a fact that my DB includes 2 entries, my Cursor gets 2 entries... but for some reason he chooses to focus on the 2nd row at the beginning after I created it - and thus exiting the while loop, even thought I called c.moveToFirst();
Maybe I'm just tired and not seeng clearly what am I doing wrong... because I compared it to other methods in my code that works fine and I cannot tell the difference between them.
My method looks like this:
public ArrayList<Kiosk> getKiosks () {
ArrayList<Kiosk> kioskArrayList = new ArrayList<>();
db = dbHandler.getWritableDatabase();
String[] columns = {Tags.TAG_LOCAL_ID, Tags.TAG_ID_SERVER, Tags.TAG_NAME,
Tags.TAG_PHONE_NUMBER, Tags.TAG_CONTACT_NAME, Tags.TAG_SCHOOL_ID};
Cursor c = db.query(DatabaseHandler.TABLE_KIOSK, columns, null, null, null, null, null);
c.moveToFirst();
Log.i("tagg", "Size of the cursor is: " + c.getCount());
while (c.moveToNext()) {
Kiosk kiosk = new Kiosk();
kiosk.setLOCAL_ID(c.getInt(c.getColumnIndex(Tags.TAG_LOCAL_ID)));
kiosk.setIdServer(c.getInt(c.getColumnIndex(Tags.TAG_ID_SERVER)));
kiosk.setName(c.getString(c.getColumnIndex(Tags.TAG_NAME)));
kiosk.setPhoneNumber(c.getString(c.getColumnIndex(Tags.TAG_PHONE_NUMBER)));
kiosk.setContactName(c.getString(c.getColumnIndex(Tags.TAG_CONTACT_NAME)));
kiosk.setSchoolId(c.getInt(c.getColumnIndex(Tags.TAG_SCHOOL_ID)));
c.moveToNext();
kioskArrayList.add(kiosk);
Log.w("taggg", "Added this to the kiosk Array: " + kiosk.getName() +
"Local ID: " + kiosk.getLOCAL_ID());
}
Log.w("tagg", "getKioskhere, size of the array I sent is: " + kioskArrayList.size());
c.close();
db.close();
return kioskArrayList;
}
My log gives clearly says the cursor's size is 2 but the ArrayList is 1:
03-11 14:18:37.334: W/(18369): School id of the client is: 1
03-11 14:18:37.336: I/(18369): Size of the cursor is: 2
03-11 14:18:37.336: W/(18369): Added this to the kiosk Array: PitaKioskLocal ID: 2
03-11 14:18:37.336: W/(18369): getKioskhere, size of the array I sent is: 1
Any advice? thanks in advance
You first move to the first element:
c.moveToFirst();
Then you move to the second one, before you even processed the first one:
while (c.moveToNext()) {
Finally, you call
c.moveToNext();
within your while loop, which leads to ignoring every second entry.
Solution: remove the call within the loop, and process the first element before moving on to the second one. The easiest method would be to change while(){} to do{} while().
Set the sort order for the query. You also do a moveToNext() prior to any work.
Cursor c = db.query(DatabaseHandler.TABLE_KIOSK, columns, null, null, null, null, Tags.TAG_LOCAL_ID + " desc");
// stuff
do {
// Iterate over cursor
} while (c.moveToNext());
It looks like you are calling moveToNext() too many times.
You start at the first row with your call moveToFirst(). Then, as you enter your while loop, moveToNext() is called again. Thus, as you enter your loop you are already sitting on the second row. Then, inside the loop, you call moveToNext() and add your kiosk too the kioskArrayList.
When you hit the top of the while loop the second time, you are sitting at an index of 2, so c.moveToNext() evaluates to false, so you only add to the list once.

Android query cursor

i have a problem with a cursor. i created a alarm manager that pick a value to compare with another in looping.
My problem is this: if the cursor is outside of the loop this pick only my first value (if exsist only one value pick only this obviously).... if the cursor is in the loop, this pick only last value (if exsist only one value pick only this obviously).
how to fix this?
my query:
public Cursor getRegistry2()
{
return (getReadableDatabase().query(
TabRegistry.TABLE_NAME,
TabRegistry.COLUMNS,
TabRegistry._ID,
null,
null,
null,
null));
my cursor in service:
Cursor c5 = databaseHelper.getRegistry2();
c5.moveToFirst();
while(c5.isAfterLast() == false){
tipe = c5.getString(c5.getColumnIndex(TabRegistry.TYPE));
status = c5.getString(c5.getColumnIndex(TabRegistry.STATUS));
number = c5.getString(c5.getColumnIndex(TabRegistry.NUMBER));
c5.moveToNext();
}
c5.close();
thanks in advance!
As I mentioned in my comment, if you are actually trying to find a particular item you need to actually look for it.
Assuming you are looking to compare the status, you might do this:
while(c5.isAfterLast() == false){
tipe = c5.getString(c5.getColumnIndex(TabRegistry.TYPE));
status = c5.getString(c5.getColumnIndex(TabRegistry.STATUS));
number = c5.getString(c5.getColumnIndex(TabRegistry.NUMBER));
if (status.equals(comparisonString)){
break;
}
c5.moveToNext();
}
This would break out of your loop, leaving your values set for the item you were looking for.
Personally, that's a lot of computing overhead and I'd just make the query to look for the comparison value directly and then check and see if the returned cursor was empty. Much simpler.
I don't understand your problem but something that is strange for me is : while(c5.isAfterLast() == false){
Have you tried to replace by while (c5.moveToNext()) { and removing c5.moveToFirst(); ?
You should know that you are overwriting the values of tipe, status and number in case your cursor has values more than one.
Cursor c5 = databaseHelper.getRegistry2();
if(c5.moveToFirst()){
do{
tipe = c5.getString(c5.getColumnIndex(TabRegistry.TYPE));
status = c5.getString(c5.getColumnIndex(TabRegistry.STATUS));
number = c5.getString(c5.getColumnIndex(TabRegistry.NUMBER));
}while(c5.moveToNext());
}
c5.close();

Categories

Resources