1

I am trying to return the names of distinct values in the 'category' column of an SQLite database. The cursor does not appear to be returning any results.

I'm building an Android app using a pre-existing database of bird species. The aim is to allow the user to explore the database through the app. The problem I'm having is in trying to return the distinct categories of bird species that exist in the database. The database appears to be opening successfully - no SQLite exception is being thrown, - but after using the query, the '.moveToNext' method does not appear to be returning any data.

public ArrayList<String> getCategory(String[] name){
        String TABLE_BIRDS = "main";
        String[] COLUMN = name;
        ArrayList<String>categories = new ArrayList<>();

        if (name[0]!=null)
        {
            Log.d(LOG_TAG, name[0]);
        } else {
            Log.d(LOG_TAG, "name[0] has not been passed");
        }
        x = db.query(true, TABLE_BIRDS, new String[] { COLUMN[0] } , null, null, COLUMN[0], null, null, null );
        if (x.moveToNext()) {
            Log.i(LOG_TAG, x.getString(x.getColumnIndex("category")));
        }
        else {
            Log.i(LOG_TAG, "The cursor is not returning any data");
        }
        //Simple cursor loop
        if (x.moveToNext()){
            String category = new String();
            category = x.getString(x.getColumnIndex(category));
            categories.add(category);
            Log.i("cursor loop", category);
        }
        return categories;

In the above code, the log messages are showing that: getCategory is receiving the expected string "category" before the query, but right after the query, the if/else loop is reporting that "The cursor is not returning any data".

What I expected is that the query would return six Strings, the cursor loop would add them to the ArrayList 'categories', and this ArrayList would be returned.

Please any help would be appreciated.

forpas
  • 160,666
  • 10
  • 38
  • 76
grainman
  • 73
  • 7

2 Answers2

1

Assuming the cursor is not null, you should iterate over the results with a while/for loop.

e.g :while(x.moveToNext()) { //your logic }

It is always useful when debugging this kind of issues to install an SQLite DB browser then check the cursor's query against your DB to see if you have any data.

  • 1
    x.moveToFirst(); and then while(x.moveToNext()) will skip the 1st row. – forpas Jul 09 '19 at 13:34
  • The cursor appears to be returning null. I have tried x.moveToFirst in the if/else test after the query, and got the same result. – grainman Jul 09 '19 at 13:36
  • @grainman if the cursor was null a null pointer exception would crash your app. – forpas Jul 09 '19 at 13:40
  • OK, I didn't know that! Could you suggest some way for me to access whatever it is returning then? – grainman Jul 09 '19 at 13:41
  • Did you check the cursor's query against the DB directly (in an sqlite browser)? To see if there's any data in it? – Calin Baciu Jul 09 '19 at 14:11
  • The query returns: "Ground-Dwelling Birds" "Small Bush Birds" "Fresh-Water Birds" "Large Bush Birds" "Sea Birds" "Shoebirds" in an SQLite browser. The data is there, but I can't see why I can't access it. – grainman Jul 09 '19 at 14:20
1

Here is a simpler version of your method:

public ArrayList<String> getCategory(String[] name) {
    String TABLE_BIRDS = "main";
    ArrayList<String> categories = new ArrayList<>();

    if (name[0] != null) {
        Log.d(LOG_TAG, name[0]);
    } else {
        Log.d(LOG_TAG, "name[0] has not been passed");
    }

    Cursor x = db.query(true, TABLE_BIRDS, new String[]{name[0]}, null, null, null, null, null, null);

    while (x.moveToNext()) {
        String category = x.getString(0);
        categories.add(category);
        Log.i("cursor loop", category);
    }

    if (x.getCount() == 0) {
        Log.i(LOG_TAG, "The cursor is not returning any data");
    }
    x.close();

    return categories;
}

I guess name[0] contains the string 'category' which is the column that you want to query.
Since you pass true as the 1st argument in the method query() this means that you will get distinct values, so no need for the group by argument.
You don't need the variable COLUMN since you have what you need in the variable name.
Also you don't need getColumnIndex() since the cursor returns only 1 column.
Edit
Instead of:

Cursor x = db.query(true, TABLE_BIRDS, new String[]{name[0]}, null, null, null, null, null, null);

try rawQuery():

Cursor x = db.rawQuery("SELECT DISTINCT " + name[0] + " FROM " + TABLE_BIRDS, null);
forpas
  • 160,666
  • 10
  • 38
  • 76
  • Thank you for your help with this. I'm still getting Log.I: The cursor is not returning any data on running the app. Could you suggest anywhere else I should be looking for the source of this problem? – grainman Jul 09 '19 at 13:56
  • Also, the 'Log.i' within the while loop is never returned. This shows that the loop is not being executed I think. – grainman Jul 09 '19 at 13:58
  • 1
    Try rawQuery(). Are you sure that name[0] contains the string category and this is the name of the column? – forpas Jul 09 '19 at 14:01
  • name[0] contains 'category'. 'category' is definitely the name of the column. – grainman Jul 09 '19 at 14:04
  • 1
    Did you try rawQuery()? – forpas Jul 09 '19 at 14:05
  • I will try rawQuery() again. I went to query() because I read that it was easier to pass the DISTINCT restriction with that. – grainman Jul 09 '19 at 14:06
  • 1
    query() is better for performance, rawQuery() is simpler for simple cases like this. Try it in the method I posted not yours. – forpas Jul 09 '19 at 14:07
  • Yes, I have tried the rawQuery(), it still gives the same Log.i: The cursor is not returning any data. – grainman Jul 09 '19 at 14:09
  • I suspect that there might be a problem with some other part of my code, possibly my DatabaseOpenHelper? – grainman Jul 09 '19 at 14:10
  • 1
    Last thing to try so you can see the sql statement as it is. Put this line before the line that executes rawQuery(): `Log.d(LOG_TAG, "SELECT DISTINCT " + name[0] + " FROM " + TABLE_BIRDS);` – forpas Jul 09 '19 at 14:12
  • Again, thank you for your help with this. This is the log output from the above: "D/DatabaseAccessCategory: category SELECT DISTINCT category FROM main" – grainman Jul 09 '19 at 14:15
  • This SELECT DISTINCT category FROM main produces: "Ground-Dwelling Birds" "Small Bush Birds" "Fresh-Water Birds" "Large Bush Birds" "Sea Birds" "Shoebirds" from my SQLite browser – grainman Jul 09 '19 at 14:16
  • 1
    The statement is fine. This means that since the cursor is not null, your table is empty. The database in the device is not the same as the database that you check with SQLite browser. – forpas Jul 09 '19 at 14:18
  • OK, so my database is saved at: app/src/main/assets/databases/birdsDatabase.db. Could this be an issue with my gradle build, or something? This is my first app, and I am not familiar with all the requirements for moving the database into the app. – grainman Jul 09 '19 at 14:23
  • The database that you are trying to query should be stored in the device where your app is executed. So you need to copy the database from assets to the device. Here some links for how to do it: https://stackoverflow.com/questions/8052262/cant-copy-sqlite-database-from-assets, https://stackoverflow.com/questions/21250468/copy-database-from-assets-folder, https://stackoverflow.com/questions/18805874/copy-database-from-assets-to-databases-folder – forpas Jul 09 '19 at 14:29
  • This is awesome, thank you for your help. I have spent hours trying to work this out so I really appreciate your knowledge! – grainman Jul 09 '19 at 14:33
  • I'm glad if this helped. – forpas Jul 09 '19 at 14:34
  • Unfortunately, my problems with this are continuing. If you would be interested, I would really appreciate your input. – grainman Jul 12 '19 at 09:49