I'm having troubles in making a rather difficult MySQL query work. I've been trying, but creating complex queries has never been my strong side.
This query includes 4 tables, which I'll describe of course.
First, we have song table, which I need to select the needed info from.
+--------------+-----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-----------+------+-----+---------+----------------+
| ID | int(6) | NO | PRI | - | auto_increment |
| Anime | char(100) | NO | | - | |
| Title | char(100) | NO | | - | |
| Type | char(20) | NO | | - | |
| Singer | char(50) | NO | | - | |
| Youtube | char(30) | NO | | - | |
| Score | double | NO | | 0 | |
| Ratings | int(8) | NO | | 0 | |
| Favourites | int(7) | NO | | 0 | |
| comments | int(11) | NO | | 0 | |
| release_year | int(4) | NO | | 2019 | |
| season | char(10) | NO | | Spring | |
+--------------+-----------+------+-----+---------+----------------+
Then we have song_ratings, which basically represents the lists of each user, since once you rate a song, it appears on your list.
+------------+----------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+----------+------+-----+-------------------+----------------+
| ID | int(11) | NO | PRI | 0 | auto_increment |
| UserID | int(11) | NO | MUL | 0 | |
| SongID | int(11) | NO | MUL | 0 | |
| Rating | double | NO | | 0 | |
| RatedAt | datetime | NO | | CURRENT_TIMESTAMP | |
| Favourited | int(1) | NO | | 0 | |
+------------+----------+------+-----+-------------------+----------------+
Users have the option to create custom lists(playlists), and this is the table which they are stored in. This is table lists.
+------------+-----------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-----------+------+-----+-------------------+----------------+
| ID | int(11) | NO | PRI | 0 | auto_increment |
| userID | int(11) | NO | MUL | 0 | |
| name | char(50) | NO | | - | |
| likes | int(11) | NO | | 0 | |
| favourites | int(11) | NO | | 0 | |
| created_at | datetime | NO | | CURRENT_TIMESTAMP | |
| cover | char(100) | NO | | - | |
| locked | int(1) | NO | | 0 | |
| private | int(1) | NO | | 0 | |
+------------+-----------+------+-----+-------------------+----------------+
And finally, the table which contains all the songs that have been added to any playlists, called list_elements.
+--------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------+------+-----+---------+----------------+
| ID | int(11) | NO | PRI | 0 | auto_increment |
| listID | int(11) | NO | MUL | 0 | |
| songID | int(11) | NO | MUL | 0 | |
+--------+---------+------+-----+---------+----------------+
What my query needs to do is list all the songs that are on the list of a user, basically these are the record in song_ratings where the userID = ?(obviously the ID of the user), but are not on a specific playlist(has no record in list_elements) where the ID/listID = ?(the ID of that playlist).
This is the query I've been using so far, but after a while I had realized this doesn't actually work the way I wanted to.
SELECT DISTINCT
COUNT(*)
FROM
song
INNER JOIN song_ratings ON song_ratings.songID = song.ID
LEFT JOIN list_elements ON song_ratings.songID = list_elements.songID
WHERE
song_ratings.userID = 34 AND list_elements.songID IS NULL
I have also tried something like this, and several variants of it
SELECT DISTINCT
COUNT(*)
FROM
song
INNER JOIN song_ratings ON song_ratings.songID = song.ID
INNER JOIN lists ON lists.userID = song_ratings.userID
LEFT JOIN list_elements ON song_ratings.songID = list_elements.songID
WHERE
song_ratings.userID = 34 AND lists.ID = 1
To make it easier, here's a SQL Fiddle, with all the necessary tables and records in them.
What you need to know. When you check for the playlist with the ID of 1, the query needs to return 23(basically all matches).
When you do the same with the ID 4, it need to return 21, if the query works correctly, because the playlist 1 is empty, thus all of the songs in the table song_ratings can be added to it(at least the ones that exist in song table, which is only half of the overall records now).
But playlist 4 already has 2 songs added to it, so only 21 are left available for adding.
Or in case the number are wrong, playlist 1 needs to return all matches. playlist 4 need to return all matches-2(because 2 songs are already added).
The userID needs to remain the same(34), and there are no records with different ID, so don't change it.
I hope I managed to explain it properlyI would suggest you failed in that endeavour, but not to worry, just see: Why should I provide an MCRE for what seems to me to be a very simple SQL query?