Query a Sqlite Database Using an Array Android - android

I have researched a handful of other forums with a similar topic and I have yet to find an answer to this frustrating issue. I am trying to use an array to check if a column in my database has one of the multiple values in the array. My cursor is as follows:
public Cursor notificationQuery(String geoIds) {
Log.e("STRINGS", geoIds);
return mDb.query(Constants.TABLE_POI_NAME,
new String[]{Constants.TABLE_COLUMN_ID, Constants.TABLE_COLUMN_POI_NAME,
Constants.TABLE_COLUMN_LATITUDE, Constants.TABLE_COLUMN_LONGITUDE,
Constants.TABLE_COLUMN_GEO_ID},
Constants.TABLE_COLUMN_GEO_ID + " IN (?)",
new String[]{geoIds},
null, null, null, null);
}
geoIds is currently an array of two values which has been converted into a string. The logged value of that string is below:
21007b0f-6b20-4eff-9a76-b412db8daa2e,26c695d6-6cb4-4c74-9933-281813a06fd9
Those are to separate Id values separated by a comma. When I test each one individually using "= ?" instead of "IN (?)" I get a proper match with the database and my cursor returns a value. However, when combined my cursor returns nothing when it should return two rows from the database. Please help me solve this issue! Thanks!

Consider a function String makePlaceholders(int len) which returns len question-marks separated with commas, then:
public Cursor notificationQuery(String geoId1,String geoId2) {
//assume we split this geoIds to 2 different values. you need to have 2 strings no 1
String[] ids = { geoId1, geoId2 }; // do whatever is needed first depends on your inputs
String query = "SELECT * FROM "+ Constants.TABLE_POI_NAME + " WHERE "+
Constants.TABLE_COLUMN_GEO_ID +" IN (" + makePlaceholders(names.length) + ")";
return mDb.rawQuery(query, ids); // ids is the table above
}
Here is one implementation of makePlaceholders(int len):
String makePlaceholders(int len) {
if (len < 1) {
// It will lead to an invalid query anyway ..
throw new RuntimeException("No placeholders");
} else {
StringBuilder sb = new StringBuilder(len * 2 - 1);
sb.append("?");
for (int i = 1; i < len; i++) {
sb.append(",?");
}
return sb.toString();
}
}

Or more simply, use the geoIds variable directly:
public Cursor notificationQuery(String geoIds) {
Log.e("STRINGS", geoIds);
return mDb.query(Constants.TABLE_POI_NAME,
new String[]{Constants.TABLE_COLUMN_ID, Constants.TABLE_COLUMN_POI_NAME,
Constants.TABLE_COLUMN_LATITUDE, Constants.TABLE_COLUMN_LONGITUDE,
Constants.TABLE_COLUMN_GEO_ID},
Constants.TABLE_COLUMN_GEO_ID + " IN (" + geoIds + ")",
null, null, null, null, null);
}
This approach is less secure but will likely give you the result you expect.

Related

Using brackets and ? in Android SQLiteDatabase query()

I'm trying to execute a query on a SQLiteDatabase in Android, using the query() function. I want to pass the argument in SelectionArgs[], but when I'm using a IN statement, it doesn't seem to substitute the '?' with the correct argument.
My query looks like this:
temp = database.query(TABLE_NAME_ENTRIES,
new String[] {"_id", "Entry", "Summary"},
"_id IN ( ? )",
new String[] {ids}, null, null, null);
and it results in an empty Cursor. Debug gives me the information that the executed query uses a statement "_id IN ( ? )", showing that it doesn't seem to replace the '?' as expected. When I change the query to
temp = database.query(TABLE_NAME_ENTRIES,
new String[] {"_id", "Entry", "Summary"},
"_id IN ( " + ids + " )",
null, null, null, null);
instead, I get the expected result.
I'm really stupid on this problem, any ideas what I'm doing wrong?
You could use a workaround like this - creating a method that generates dynamically your string with ? and , and put it in the query like this:
String[] ids = { "id1", "id2" }; // do whatever is needed first
String query = "SELECT * FROM table"
+ " WHERE _id IN (" + makePlaceholders(ids.length) + ")";
Cursor cursor = mDb.rawQuery(query, ids);
String makePlaceholders(int len) {
if (len < 1) {
// It will lead to an invalid query anyway ..
throw new RuntimeException("No placeholders");
} else {
StringBuilder sb = new StringBuilder(len * 2 - 1);
sb.append("?");
for (int i = 1; i < len; i++) {
sb.append(",?");
}
return sb.toString();
}
}
P.S. I think that the spaces before and after the question mark in your query could be wrong there, but I didn't test it, so I can't be 100% sure

Dynamic SQLite queries

I'm trying to implement dynamic queries in my Android app, to let the users search according to some criteria. In this case I'm trying to search simply by an integer value. Here's my attempt:
...
public String[][] listarNegocio(int idProyecto,
int minimo,
int maximo)
{
String[][] arrayDatos = null;
String[] parametros = {String.valueOf(idProyecto)};
Cursor cursor = null;
cursor = querySQL("SELECT *" +
" FROM negocio" +
" WHERE ? in (0, id_proyecto)", parametros);
if(cursor.getCount() > 0)
{
int i = minimo - 1;
arrayDatos = new String[maximo - minimo + 1][20];
while(cursor.moveToNext() && i < maximo)
{
// Here I fill the array with data
i = i + 1;
}
}
cursor.close();
CloseDB();
return(arrayDatos);
}
public Cursor querySQL(String sql, String[] selectionArgs)
{
Cursor oRet = null;
// Opens the database object in "write" mode.
db = oDB.getReadableDatabase();
oRet = db.rawQuery(sql, selectionArgs);
return(oRet);
}
...
I tested this query using SQLFiddle, and it should return only the rows where the column id_proyecto equals the parameter idProyecto, or every row if idProyecto equals 0. But it doesn't return anything. If I remove the WHERE clause and replace "parametros" with "null", it works fine.
Additionally, I need to search by text values, using LIKE. For example, WHERE col_name LIKE strName + '%' OR strName = ''. How should I format my parameters and the query to make it work?
You should do one query for each case. For an id that exists, do SELECT * FROM negocio WHERE id_proyecto = ?. For an id that doesn't exist (I'm assuming 0 isn't a real id), just query everything with SELECT * FROM negocio.
Code should be something like this:
if(parametros[0] != 0){
cursor = querySQL("SELECT *" +
" FROM negocio" +
" WHERE id_proyecto = ?", parametros);
} else {
cursor = querySQL("SELECT *" +
" FROM negocio", null);
}
Regarding your second question, it depends on what you're looking for, you could use LIKE '%param%' or CONTAINS for occurrences in between text, LIKE param for partial matches or just = param if you're looking an exact match.

How to use WHERE IN clause in Android Sqlite?

I am trying to execute an single update query where i have to update a single field for many persons.
Now the below query works :-
UPDATE PERSON SET ISSELECTED=1 WHERE ID IN (132,142,115,141,41,133,40,56,139,134,135,65,143,9,64,39,120,104,122,35,19,98,124,127,130,136,119,123,55,102,5,128,140,95,138,131,96,93,129,103,94,89,126,21,29,125,3,101,92,113,4,88,111,63,60,38,114,90,31,118,99,121,117,100,112,97,25,116,10,32,27,30,14,26,12,61,57,20,107,110,91,109,108,106,105,16,62,33,59,18,58,36,11,15,37,28,24,6,7,8,34,13)
But it does not return the number of updated rows when used with execSql or rawQuery
I am trying to form this query using the update method which returns the no. of rows affected
int rowsUpdatedSelected = db.update("PERSON", values, "ID" + " = ?", new String[] {id.toString()});
// where id is a StringBuilder object containing the ids like above
But this is not working.
You can write a method to make IN query string and use that as you selectionArgs. Like below
selectionArgs = idArray; // Where id array will be String[] and will contain all of your ids
selection = "ID" + makeInQueryString(idArray.length);
Where makeInQueryString() is
/**
* Creates where string which can be used for IN query. It creates string
* containing "?" separated by ",". This method can be used as below <br>
* ColumnName + makeInQueryString(size) <br>
* This will create IN query for provided column name.
*
* #param size
* size of the items
* #return IN query string of the form (?,?,?,?)
*/
public static String makeInQueryString(int size) {
StringBuilder sb = new StringBuilder();
if (size > 0) {
sb.append(" IN ( ");
String placeHolder = "";
for (int i = 0; i < size; i++) {
sb.append(placeHolder);
sb.append("?");
placeHolder = ",";
}
sb.append(" )");
}
return sb.toString();
}
Try this code.
Put single quote on your in you IN data
UPDATE PERSON SET ISSELECTED=1 WHERE ID IN ('132','142','115','14','1');
I didn't try this.. just give a try.. and let me know wethr its working or not..
int rowsUpdatedSelected = db.update("PERSON", values, "ID IN (?)", new String[] {id.toString()});
You can try using sqlite3_changes() for this:
This function returns the number of database rows that were changed or
inserted or deleted by the most recently completed SQL statement on
the database connection specified by the first parameter. Only changes
that are directly specified by the INSERT, UPDATE, or DELETE statement
are counted.
So after your update statement, add this code:
Cursor cursor = null;
try
{
cursor = db.rawQuery("SELECT changes() AS updated_row_count", null);
if(cursor != null && cursor.getCount() > 0 && cursor.moveToFirst())
{
final long count = cursor.getLong(0);
Log.d("LOG", "no. of updated rows : " + count);
}
} catch(SQLException e)
{
e.printStackTrace();
} finally
{
if(cursor != null)
{
cursor.close();
}
}
Hope this helps.

Updating a single column is creating sqlite syntax error

I'm not sure what I'm doing wrong, but I'm trying to update a single integer value in a column of a table to 1 from 0. When creating the database, I set all values of the column to zero using:
for (int i = 0; i < setups.length; i++) {
ContentValues values = new ContentValues();
values.put(JokeDbContract.TblJoke.COLUMN_NAME_SETUP, setups[i]);
values.put(JokeDbContract.TblJoke.COLUMN_NAME_PUNCHLINE, punchlines[i]);
values.put(JokeDbContract.TblJoke.COLUMN_NAME_USED, 0);
db.insert(JokeDbContract.TblJoke.TABLE_NAME, null, values);
}
Then, in the actual activity, I'm doing:
private void findNewJoke() {
JokeDb jokeDb = JokeDb.getInstance(this);
SQLiteDatabase theDb = jokeDb.getDB();
String selection = JokeDbContract.TblJoke.COLUMN_NAME_USED + "=" + 0;
// Query database for a joke that has not been used, update the fields
// theJoke and thePunchline appropriately
String[] columns = {JokeDbContract.TblJoke._ID,
JokeDbContract.TblJoke.COLUMN_NAME_PUNCHLINE,
JokeDbContract.TblJoke.COLUMN_NAME_SETUP,
JokeDbContract.TblJoke.COLUMN_NAME_USED};
Cursor c = theDb.query(JokeDbContract.TblJoke.TABLE_NAME, columns, selection,
null, null, null, null);
if (c.moveToFirst() == false) {
Toast.makeText(this, R.string.error_retrieving_joke, Toast.LENGTH_LONG).show();
Log.e(getString(R.string.app_name),"No jokes retreived from DB in JokeActivity.findNewJoke()!");
}
else {
ContentValues values = new ContentValues();
theSetup = c.getString(c.getColumnIndexOrThrow(JokeDbContract.TblJoke.COLUMN_NAME_SETUP));
thePunchline = c.getString(c.getColumnIndexOrThrow(JokeDbContract.TblJoke.COLUMN_NAME_PUNCHLINE));
String updateSelection = JokeDbContract.TblJoke.COLUMN_NAME_SETUP + "=" + theSetup;
values.put(JokeDbContract.TblJoke.COLUMN_NAME_USED, 1);
theDb.update(JokeDbContract.TblJoke.TABLE_NAME, values, updateSelection, null);
}
}
I'm getting an error on the update:
java.lang.RuntimeException: .... while compiling: UPDATE jokes SET used=?
WHERE setup=Why do programmers always mix up Halloween and Christmas?
It seems as though I'm not getting an actual value set for the used column. What the program ultimately does is cycle through jokes where used=0, then sets used to 1 when it has been viewed. So the query only pulls those jokes that aren't used yet. I have a feeling I'm missing something simple, one can hope.
I think you are having problems with quotation marks.
Example:
String updateSelection = JokeDbContract.TblJoke.COLUMN_NAME_SETUP + "=\"" + theSetup + "\"";
However, the recommended way to do this, would be:
theDb.update(JokeDbContract.TblJoke.TABLE_NAME, values, JokeDbContract.TblJoke.COLUMN_NAME_SETUP + " = ?", new String[] { theSetup });
It is better to use field = ?, because this helps sqlite cache queries (I believe).

Android content provider query IN clause

Is possible to use an IN clause for a content provider?
I am currently using
cursor = contentResolver.query(CONTENT_URI, PROJECTION, "field IN (?)", new String[] { argsBuilder.toString() }, null);
If i remove the (?) and just use ? I get an error.
I get 0 count in my cursor.
If I type manually and execute the query in sqlite3 it works.
Help?
When using the IN operator, you need to have one ? separated by a comma per argument you provide in your selectionArgs array. E.g.:
String[] selectionArgs = {"red", "black"};
String selection = "color IN (?, ?)";
The following picks the right count and the proper args:
int argcount = 2; // number of IN arguments
String[] args = new String[]{ 1, 2 };
StringBuilder inList = new StringBuilder(argcount * 2);
for (int i = 0; i < argcount; i++) {
if(i > 0) {
inList.append(",");
}
inList.append("?");
}
cursor = contentResolver.query(
CONTENT_URI,
PROJECTION,
"field IN (" + inList.toString() + ")",
args,
null);
If your arguments are numbers only, this works as well:
Iterable args = ...; // any array, list, set, ...
cursor = contentResolver.query(CONTENT_URI, PROJECTION, "field IN (" + TextUtils.join(",", args) + ")", null, null);
This is a code snippet from my application built in Kotlin, the params array is for illustration purposes only as the parameters come from elsewhere in the code.
The problem with most of the proposed solutions is that they result in the loss of the SQL injection prevention that the use of placeholders provides, so I only use an expression that returns an array of "?" and whose quantity matches the array of provided parameters and then becomes a comma separated String.
That way, the delivered string is a string of placeholders and not the parameters directly.
Sorry for my first answer write in spanish.
var params = arrayOf("1789","1787","1694","1784")
applicationContext.contentResolver.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
null,
"_ID IN (" + Array(params.size) { "?" }.joinToString() + ")",
params,
null
)

Categories

Resources