javasqldatabasesqliteandroid-studio

Retrieving all records with 'connection status' using SQLite and Java


I'm working on an Android application that utilizes a SQLite database to store and manage music data. I've encountered an issue with a method in my DatabaseHelper class that aims to retrieve all bands associated with a specific song, along with their connection status. So all band names (band_name) from the bands table should be returned and when the band_id is contained in the songs_bands table the boolean isConnected should be set to 1, otherwise the isConnected will be 0.

The method receives an int value for the songId parameter and is expected to return a List of BandInfo objects. Each BandInfo object should contain the band's ID, name, and a boolean value indicating whether the band is connected to the specified song (isConnected).

Here is the method from DatabaseHelper:

    public List<BandInfo> getAllBandsWithConnectionStatus(int songId) {
        List<BandInfo> bandList = new ArrayList<>();
        SQLiteDatabase db = this.getReadableDatabase();

        // Query to retrieve all bands with connection status for a specific song
        String[] columns = {"bands._id", "bands.band_name", "CASE WHEN songs_bands.band_id IS NULL THEN 0 ELSE 1 END AS is_connected"};
        String selection = "songs_bands.song_id = ?";
        String[] selectionArgs = {String.valueOf(songId)};

        Cursor cursor = db.query(
                "bands LEFT JOIN songs_bands ON bands._id = songs_bands.band_id",
                columns,
                selection,
                selectionArgs,
                null,
                null,
                null
        );

        if (cursor.moveToFirst()) {
            int idColumnIndex = cursor.getColumnIndex("_id");
            int nameColumnIndex = cursor.getColumnIndex("band_name");
            int isConnectedColumnIndex = cursor.getColumnIndex("is_connected");

            do {
                int bandId = cursor.getInt(idColumnIndex);
                String bandName = cursor.getString(nameColumnIndex);
                int isConnected = cursor.getInt(isConnectedColumnIndex);

                BandInfo bandInfo = new BandInfo(bandId, bandName, isConnected == 1);
                bandList.add(bandInfo);
            } while (cursor.moveToNext());
        }

        cursor.close();
        // Print the list of BandInfo objects before returning
        for (BandInfo bandInfo : bandList) {
            Log.d("SplashActivityZZ", "(DatabaseHelper) BandInfo in list: " + bandInfo.toString());
        }
        return bandList;
    }

The problem arises when I execute this method. Instead of returning a complete List of BandInfo objects, the bandList only contains the connected bands. The non-connected bands are not included in the list.

I've tried modifying the query and checking for any potential errors in the code, but I haven't been able to resolve the issue. I'm hoping to get some insights on how to correctly retrieve all bands, including those not connected to the specified song, and set their isConnected boolean accordingly.

Here are the two tables used within this query - first the bands:

    private static final String SQL_CREATE_BANDS_TABLE =
            "CREATE TABLE " + DatabaseContract.Bands.TABLE_NAME + " (" +
                    DatabaseContract.Bands._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
                    DatabaseContract.Bands.COLUMN_BAND_NAME + " TEXT NOT NULL, " +
                    DatabaseContract.Bands.COLUMN_BAND_DESCRIPTION + " TEXT)";

and the user_bands:

    private static final String SQL_CREATE_USER_BANDS_TABLE =
            "CREATE TABLE " + DatabaseContract.UserBands.TABLE_NAME + " (" +
                    DatabaseContract.UserBands._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
                    DatabaseContract.UserBands.COLUMN_USER_ID + " INTEGER, " +
                    DatabaseContract.UserBands.COLUMN_BAND_ID + " INTEGER, " +
                    "FOREIGN KEY (" + DatabaseContract.UserBands.COLUMN_USER_ID + ") REFERENCES " +
                    DatabaseContract.Users.TABLE_NAME + "(" + DatabaseContract.Users._ID + "), " +
                    "FOREIGN KEY (" + DatabaseContract.UserBands.COLUMN_BAND_ID + ") REFERENCES " +
                    DatabaseContract.Bands.TABLE_NAME + "(" + DatabaseContract.Bands._ID + "))";

Any assistance would be greatly appreciated.


Solution

  • To get this to work I changed the query, keeping the LEFT JOIN but removing the CASE as that seemed to be causing the problems. I am now evaluating the join in the do while loop to determine whether there is a connection between the two tables and if there is I am setting the isConnected flag to 'true' and if there is not setting to 'false'. From here I add it into the bandList class object.

    Here is the adjusted query which now returns everything from the bands table and sets the flag isConnected when the band_id also exists within the songs_bands table for the song_id being investigated:

    public List<BandInfo> getAllBandsWithConnectionStatus(int songId) {
        removeDuplicateSongBandPairs();
        List<BandInfo> bandList = new ArrayList<>();
        SQLiteDatabase db = this.getReadableDatabase();
    
    
        // Query to retrieve all bands with connection status for a specific song
        String[] columns = {"bands._id", "bands.band_name", "songs_bands.band_id AS isConnected"};
        String selection = null;  // No need for a WHERE clause
        String[] selectionArgs = {String.valueOf(songId)};
    
        Cursor cursor = db.query(
                "bands LEFT JOIN songs_bands ON bands._id = songs_bands.band_id AND songs_bands.song_id = ?",
                columns,
                selection,
                selectionArgs,
                null,
                null,
                null
        );
    
        if (cursor.moveToFirst()) {
            int idColumnIndex = cursor.getColumnIndex("_id");
            int nameColumnIndex = cursor.getColumnIndex("band_name");
            int isConnectedColumnIndex = cursor.getColumnIndex("isConnected");
    
            do {
                int bandId = cursor.getInt(idColumnIndex);
                String bandName = cursor.getString(nameColumnIndex);
                int isConnected = 0;
                Log.d("SplashActivityZZ", "(DatabaseHelper) line #564 - cursor.getString(isConnectedColumnIndex)" + cursor.getString(isConnectedColumnIndex));
                if (!cursor.isNull(isConnectedColumnIndex)) {
                    if (isConnectedColumnIndex > 0) {
                        isConnected = 1;
                    }
                    else {
                        isConnected = 0;
                    }
                    Log.d("SplashActivityZZ", "(DatabaseHelper) line #567 - cursor.getInt(isConnectedColumnIndex): " + cursor.getInt(isConnectedColumnIndex));
                }
                BandInfo bandInfo = new BandInfo(bandId, bandName, isConnected == 1);
                bandList.add(bandInfo);
    
                // Log the band information
                Log.d("SplashActivityZZ", "(DatabaseHelper) line #574 - BandInfo in list: " + bandInfo.toString());
            } while (cursor.moveToNext());
        }
        cursor.close();
        return bandList;
    }