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, ...);
Related
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).
I'm having some trouble finding any info about this problem, but it appears to be a limitation of SQLite.
Consider a simple words table with 2 fields, _id (int) and word (text). The following query works and returns the expected results (all words which are 12 characters or less):
SELECT * FROM words WHERE LENGTH(word) <= 12;
However if this character limit needs to be dynamic and made into a parameter, the query no longer works.
It returns all rows of the table:
String query = "SELECT * FROM words WHERE LENGTH(word) <= ?";
Cursor cursor = database.rawQuery(query, new String[]{ Integer.toString(12) });
I also tried selecting the length as a new column, then applying the condition to that, but it gives the same results:
String query = "SELECT w.*, LENGTH(w.word) AS word_length FROM words w WHERE word_length <= ?";
Cursor cursor = database.rawQuery(query, new String[]{ Integer.toString(12) });
Is my only option to just filter through the query results afterward? Why do parameterized conditions on normal INT columns work but not on LENGTH()? (e.g. WHERE _id < ? works fine)
The sql statement that is executed with:
rawQuery(query, new String[]{ Integer.toString(12) });
is:
SELECT * FROM words WHERE LENGTH(word) <= '12';
and not:
SELECT * FROM words WHERE LENGTH(word) <= 12;
because rawQuery() treats all the passed parameters as strings and encloses all of them inside single quotes.
So the integer LENGTH(word) is compared to a string literal like 12 and this is where exists a feature of SQLite which states that:
An INTEGER or REAL value is less than any TEXT or BLOB value.
(from Datatypes In SQLite Version 3).
So all integers are considered less than the string literal '12'.
Of course this is not what you want and expect, so what you can do is force a conversion of '12' to the integer 12 and you can do it by adding 0 to it:
String query = "SELECT * FROM words WHERE LENGTH(word) <= ? + 0";
What this does is an implicit conversion of '12' to 12 because you apply to it a numeric operation.
Of course as soon as I rubber duck this I'm able to figure out a workaround by casting the field to an integer:
String query = "SELECT * FROM words WHERE CAST(LENGTH(word) AS INTEGER) <= ?";
Cursor cursor = database.rawQuery(query, new String[]{ Integer.toString(12) });
Seems excessive but I guess the return value of LENGTH() isn't considered an integer (all documentation I've come across just says it "returns the number of characters")
Did you try Integer.parseInt() ? I think your query need's integer parameter and you are converting it to string :)
I have 2 ResultSets. 1st ResultSet contains the records from table1 from database1 and 2nd ResultSet contains the records from table2 from database2. I need a list of records from resultset1 which are not present in resultSet2. For this I wrote this logic but it is not working and throwing me the following error.
java.sql.SQLException: Invalid operation for read only resultset: deleteRow
if ( table1ResultSet != null )
{
while ( table1ResultSet.next() )
{
final String table1Record = table1ResultSet.getString( 1 );
if ( table2ResultSet != null )
{
while ( table2ResultSet.next() )
{
final String table2Record = table2ResultSet.getString( 1 );
if ( table1Record.toString().equalsIgnoreCase( table2Record.toString() ) )
{
table1ResultSet.deleteRow();
break;
}
}
}
}
}
return table1ResultSet;
That exception says what the problem is - your result set doesn't support delete. In order to have updateable result set there are some requirements:
When you prepare statement did you make it with ResultSet.CONCUR_UPDATABLE?
A query can select from only a single table without any join operations.
The query must select all non-nullable columns and all columns that do not have a default value. A query cannot use "SELECT * ". Cannot select derived columns or aggregates such as the SUM or MAX of a set of columns.
You might want to move the results sets into Java sets before working doing what you are doing though because using deleteRow will actually delete the row from the database (unless that's the expected result)
There is another problem with your code though. Even if delete works your code will fail on the second iteration of result set 1 because you never reset table2ResultSet and for the second iteration there won't be more results in table2resulset.
But on top of all that. Why would you go through all that hussle and get all that rows that you don't need instead of doing it with one single query like:
select * from table 1 where id not in select id from table 2
or
delete from table 1 where id not in select id from table 2
if that's the goal
Your logic:
Assumes the records come in some order (which may or may not be true, depending on your SQL)
Consumes the entire result set 2 for each row of result set 1, which is unlikely your intent
Deletes things, which is also not what you mentioned in the question
Your question can be implemented easily as such:
Set<String> list1 = new HashSet<>();
while (table1ResultSet.next())
list1.add(table1ResultSet.getString(1).toLowerCase());
while (table2ResultSet.next())
list1.remove(table2ResultSet.getString(1).toLowerCase());
System.out.println(list1);
This will print all the values (without duplicates) that are present in the first result set, but not in the second.
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.
I'm new to SQLite and Java, and I'm trying to learn things on the fly. I have a column that has some numeric values in it, and I would like to get the sum of it and display it in a textview.
My current code is this:
public Cursor getTotal() {
return sqliteDatabase2.rawQuery(
"SELECT SUM(COL_VALUES) as sum FROM myTable", null);
}
I'm not sure if that code is correct, though.
I know that I'm supposed to fetch the results of that code, but I'm unsure how to do it. How can I get the results of this query into my Java code?
The sum will be returned as a result with one row and one column so you can use the cursor to fetch that value:
Cursor cursor = sqliteDatabase2.rawQuery(
"SELECT SUM(COL_VALUES) FROM myTable", null);
if(cursor.moveToFirst()) {
return cursor.getInt(0);
}