sqlite fetching data using foreign key: Cannot bind argument at index 1 because the index is out of range. The statement has 0 parameters

I am trying to fetch a record from the sqlite database in Android, and having trouble. It often throws java.lang.IllegalArgumentException and gives me the same message.

 mListSongs = mSongDao.getSelectedSongs(artist_id);



public List<Song> getSelectedSongs(Long artistId) {
    List<Song> listSongs = new ArrayList<Song>();
    String selectQuery = "SELECT " + DBHelper.SONG_PATH + " FROM " + DBHelper.TABLE_SONG + " s, "
            + DBHelper.TABLE_ARTIST + " a WHERE s."
            + DBHelper.SONG_ID + " = a.'" + DBHelper.ARTIST_ID + "'";               
    String[] selectionArgs = new String[]{String.valueOf(artistId)};
    Cursor cursor;

    cursor = mDatabase.rawQuery(selectQuery, selectionArgs);



    cursor.moveToFirst();

    while (!cursor.isAfterLast()) {
        Song song = cursorToSelectSong(cursor);
        listSongs.add(song);
        cursor.moveToNext();
    }
    cursor.close();
    return listSongs;
}
private Song cursorToSelectSong(Cursor cursor) {Song song = new Song(); song.setmSong_path(cursor.getString(3)); return song;}

Solution 1:

The issue is that you are supplying an argument, as per String[] selectionArgs = new String[]{String.valueOf(artistId)}; and then cursor = mDatabase.rawQuery(selectQuery, selectionArgs); but that the statement (the SELECT statement) has no place-holder (an ?) within it.

So you have 1 argument but the statement has 0 parameters to substitute the argument for.

Changing :-

String selectQuery = "SELECT " + DBHelper.SONG_PATH + " FROM " + DBHelper.TABLE_SONG + " s, "
        + DBHelper.TABLE_ARTIST + " a WHERE s."
        + DBHelper.SONG_ID + " = a.'" + DBHelper.ARTIST_ID + "'";

to :-

String selectQuery = "SELECT " + DBHelper.SONG_PATH + " FROM " + DBHelper.TABLE_SONG + " s, "
        + DBHelper.TABLE_ARTIST + " a WHERE s."
        + DBHelper.SONG_ID + "=?";

Introduces the parameter and it, the ?, will be substituted for the artist_id passed to the method.

Alternately using :-

String selectQuery = "SELECT " + DBHelper.SONG_PATH + " FROM " + DBHelper.TABLE_SONG + " s, "
    + DBHelper.TABLE_ARTIST + " a WHERE s."
    + DBHelper.SONG_ID + " =" + String.valueOf(artist_id);

along with :-

cursor = mDatabase.rawQuery(selectQuery, null);

would also work BUT is open to SQL injection (but not really as it's a long that has been passed, which cannot be a String that could contain dangerous SQL).

  • i.e. no arguments are passed into rawQuery and therefore there is no expectation that the statement should contain a parameter place-holder (?).

However, there is no need to JOIN the ARTIST table as the SONG table has the ARTIST_ID column.

  • You'd only need the JOIN if you wanted other details about the ARTIST e.g. artist name (which you probably already know as you've ascertained the ARTIST_ID when invoking the method).

As such the simplified :-

String selectQuery = "SELECT " + DBHelper.SONG_PATH + " FROM " + DBHelper.TABLE_SONG + " WHERE " + DBHelper.SONG_ID + "=?";

would suffice.

Regarding Cursor issues I'd suggest trying :-

cursor = mDatabase.rawQuery(selectQuery, selectionArgs);
DatabaseUtils.dumpCursor(cursor); //<<<<<<<<<< will output the contents of the cursor to the log
while(cursor.moveToNext()) {
    String songpath = cursor.getString(cursor.getColumnIndex(DBHelper.SONG_PATH));
    Log.d("EXTRACTEDPATH", "Extracted PATH " + songpath); //<<<<<<<<<< output extracted path to the log
    Song newsong = new Song();
    newsong.setmSong_path(songpath);
    listSongs.add(newsong);
}
cursor.close();
return listSongs;

}

  • Dumps the Cursor immediately after it is retrieved
  • Uses simpler loop
  • Uses column name to derive the column offset
  • outputs the data from the column (if it shows path in log, but you still get empty path in list then it's either setmSong_path that is wrong or how you are getting data from the List.)

Solution 2:

I think you want to fetch a list of songs by an artist, providing the artistId.
I believe that in in each row of the songs table DBHelper.TABLE_SONG there is a column for the id of the artist. If there isn't it should be.
Change your sql statement to this:

String selectQuery = "SELECT " + DBHelper.SONG_PATH + " FROM " + DBHelper.TABLE_SONG + " WHERE " + DBHelper.ARTIST_ID + " = ?";

As I said there must be a column DBHelper.ARTIST_ID or similar to identify the artist of each song.
The ? is the 1 parameter and its value will be artistId.