1
public void DBSearchCategory(String tableName) {
    // 1st way 
    String inClause = s1.ListViewCategory.toString();
    inClause = inClause.replace("[", "(");
    inClause = inClause.replace("]", ")");

   //        Cursor cursor = database.rawQuery("SELECT CATEGORY FROM " + tableName
  //                + " WHERE CATEGORY NOT IN " + inClause
 //                + " ORDER BY RANDOM() LIMIT 1 ", null);

    // 2nd way
    try {
        StringBuilder sb = new StringBuilder("");
        for (String param : s1.ListViewCategory) {
            sb.append(",").append('"').append(param).append('"');
        }
        params = sb.toString().substring(1); 
        Log.v("Tag", "params value is " + params);
    } catch (StringIndexOutOfBoundsException e) {

    }
    Cursor cursor = database.rawQuery("SELECT CATEGORY FROM " + tableName
                    + " WHERE CATEGORY NOT IN (?) "
                    + " ORDER BY RANDOM() LIMIT 1 ", new String[]{params});

    while (cursor.moveToNext()) {
        category = cursor.getString(cursor.getColumnIndex("CATEGORY"));
        s1.keyCategory = category;
    }
    cursor.close();
}
  1. s1.ListViewCategory is a String type ArrayList in Singleton class s1, and it has values of categories: "game","country","city","subway","actor","pet" // In Database there are total 33 categories, and I want to exclude these 6 categories that are in s1.ListViewCategory

  2. In rawQuery, I want to exclude categories that are in s1.ListViewCategory, so I tried 2 ways of cursor refering to these 2 stackoverflow questions: Android - sqlite in clause using string values from array? ///Android - sqlite in clause using values from array

I used WHERE and NOT IN statement to exclude these 6 categories

  1. When I tried 2nd way cursor, I got no error. However, the Sql query did not work. It had to exclude categories that are in String[params], but it did not work. So I used log to see what param is and I got this

    2020-01-09 09:16:47.233 8978-8978/com.kj.word V/Tag: params value is "game","country","city","subway","actor","pet"

  2. When I tried 1st Cursor Category, I got error logcat:

    Error Code : 1 (SQLITE_ERROR)
    Caused By : SQL(query) error or missing database.
    (no such column: game (code 1): , while compiling: SELECT CATEGORY FROM KeyWordDB WHERE CATEGORY 
    NOT IN (game, country, city, subway, actor, pet) ORDER BY RANDOM() LIMIT 1)
    #################################################################
    at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
    at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:1008)
    at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:573)
    at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
    at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:59)
    at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
    at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:44)
    at android.database.sqlite.SQLite
    

I confirmed that there is a database, so I guess it is probably sql query problem ...

  1. So my question is How can I fix 1st or 2nd cursor to exclude categories that are in s1.ListViewCateogry?

I've searched real hard, but I wasn't able to find answer... Ill be real grateful, if someone answers this question

1 Answer 1

1

Change the double quotes with single quotes inside the loop that constructs the comma delimited list:

for (String param : s1.ListViewCategory) {
    sb.append(",").append("'").append(param).append("'");
}
params = sb.toString().substring(1); 

This code constructs a list like:

'game', 'country', 'city', 'subway', 'actor', 'pet'

If you use it as a parameter in the rawQuery() method then this list will be treated as a string literal and not a list of values.
So do this instead:

String sql = "SELECT CATEGORY FROM " + tableName
             + " WHERE CATEGORY NOT IN (?) "
             + " ORDER BY RANDOM() LIMIT 1 ";
sql = sql.replace("?", params);
Cursor cursor = database.rawQuery(sql, null);

Note that this method is prone to sql injection.

Another way is to create a list of ? placeholders instead of 1 placeholder and pass the list of values as an array of strings like this:

for (String param : s1.ListViewCategory) {
    sb.append(",?");
}
String[] array = ListViewCategory.toArray(new String[s1.ListViewCategory.size()]);

params = sb.toString().substring(1);
String sql = "SELECT CATEGORY FROM " + tableName
           + " WHERE CATEGORY NOT IN (@) "
           + " ORDER BY RANDOM() LIMIT 1 ";
sql = sql.replace("@", params);

Cursor cursor = database.rawQuery(sql, array);
Sign up to request clarification or add additional context in comments.

17 Comments

Remopve the try/catch block to check if there is any error. Also what is the result of: Log.v("Tag", "params value is " + params);?
@Korea19800 see another safer way to do it in my edited answer.
Thanks a lot! I will try and ask again if it has errors. Also I will select your answer if there is no error! Thanks a lot again
The statement uses NOT IN which means it excludes everything in the list (which must have at least 1 item, right?). So either it works or not. Did you try both ways?
I can't reproduce your issue. You will have to debug to check the sql statement right after: sql = sql.replace("?", params); and log its value if it is as it should be.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.