Android Sqlite selection args[] with int values
The answer is in the title: you are trying to pass integer values into the query, but what you actually end up with are string values.
This is a horrible design bug in the Android database API; you can use parameters only for strings.
Integer numbers do not have the formatting and SQL injection problems that string values would have, so you can just insert the numbers directly into the SQL expression:
Cursor c = database.query(
DATABASE_TABLE, columns,
KEY_YEAR + "=" + year + " AND " +
KEY_MONTH + "=" + month + " AND " +
KEY_DAY + "=" + day,
null, null, null,
KEY_MONTH + "," + KEY_DAY);
(And the orderBy
syntax was wrong.)
Using int value in selection args argument of sqlite for android
Yes, you can use the following ways to convert int
to String
.
int i=10;
String[] str = new String[]{String.valueOf(i)};
String[] str1 = new String[]{Integer.toString(i)};
Android Sqlite selection args[] incorrect value?
The documentation for SQLiteDatabase.query()
says:
selectionArgs - You may include ?s in selection, which will be replaced by the values from selectionArgs, in order that they appear
in the selection. The values will be bound as Strings.
When you execute this query:
SELECT * FROM item WHERE (arg1=40 OR arg2=42) AND arg3=false
and bind the arguments using the selectionArgs
-parameter, the integers and the boolean will be bound as strings. This is not the same as in your database. I know you said all your columns are of type TEXT
, but read the SQLite Documentation:
The type affinity of a column is the recommended type for data stored
in that column. The important idea here is that the type is
recommended, not required. Any column can still store any type of
data. It is just that some columns, given the choice, will prefer to
use one storage class over another.
That means, when you insert your integer values in your string-table, SQLite will convert those and store them as integers. The next important point is comparison:
SQLite may attempt to convert values between the storage classes
INTEGER, REAL, and/or TEXT before performing a comparison.
[...]
- An expression that is a simple reference to a column value has the same affinity as the column.
The docs give the following example:
CREATE TABLE t1(
a TEXT, -- text affinity
b NUMERIC, -- numeric affinity
c BLOB, -- no affinity
d -- no affinity
);
-- Because column "a" has text affinity, numeric values on the
-- right-hand side of the comparisons are converted to text before
-- the comparison occurs.
SELECT a < 40, a < 60, a < 600 FROM t1;
0|1|1
In your case that means the following:
- Your
TEXT
-table gets integers inserted, which are then converted (and stored) asINTEGER
s. - When performing your comparison, you give in
TEXT
-values (which are your integers). Those should be (but don't need to be) converted toTEXT
-values, because your table indicates it's values are of typeTEXT
. - You compare
INTEGER
toTEXT
, which is not equal and therefor doesn't give you the correct results.
To insert different data-types (other then string) into the SQLiteDatabase, use Prepared Statements.
Android SQLite query with integer parameter
Second option with ?
is the suggested way of using query method.
selectionArgs: You may include ?s in selection, which will be replaced by the values
from selectionArgs, in order that they appear in the selection. The
values will be bound as Strings.
selectionArgs in SQLiteQueryBuilder doesn't work with integer values in columns
According to SQLite documentation,
Any column in an SQLite version 3 database, except an INTEGER PRIMARY KEY column, may be used to store a value of any storage class.
In context of my case, that means that we can't be sure what data type will be stored in columns. If you can control and convert data types when they're putting into database - you can convert id
values to TEXT
when adding data to database and use selectionArgs
easily. But it's not an answer for my question, because I have to deal with database content as is.
So, possible solutions:
a) embed integer values in selection
string without wrapping them into '
:
cursor = builder.query(db,
new String[]{"col1", "col2", "col3"},
"id = " + getSID(db), null, null, null, null);
b) cast values from selectionArgs: CAST(? as INTEGER)
or CAST(id AS TEXT)
. I think, converting column to TEXT
is better solution, because right operand is always TEXT
, but the left one can be anything. So:
cursor = builder.query(db,
new String[]{"col1", "col2", "col3"},
"CAST(id AS TEXT) = ?",
new String[]{getSID(db)}, null, null, null);
Related Topics
Disable Home Button in Android Ics (4.0)
How to Store Image Retrieved from Url in a SQLite Database
Which Port and Protocol Does Google Cloud Messaging (Gcm) Use
Adb Cannot Start Daemon, Createprocess Failure, Error 2
Live Character Count for Edittext
Android Getting an Image from Gallery Comes Rotated
Lame Mp3 Encoder Compile for Android
Android: Autocomplete Textview Similar to the Facebook App
Opencv Android Green Color Detection
How to Create Custom Shape Button with Selector in Android
Implementing a Simple Dagger2 Sample
Differencebetween Sendstickybroadcast and Sendbroadcast in Android