简体   繁体   中英

How can I return all relationship data in one mysql query and stop only one result being concatanated when querying by relationship

I am trying to perform a MYSQL query which retrieves relationship data and concats it into an concatanated string of json objects which I later json_decode.

I have set up a fiddle here but JSON_OBJECT does not work. The schema is there or below in markdown table.

The final result of what I would like to acheive is the results in the table below.

id title date_published artists genres
1 My Song 2022-01-01 15:00:01 [{id: 1, name: 'Pauli', is_featuring: 0}, {id: 2, name: 'Tony', is_featuring: 1}] [{id: 1, name: 'Rock'}, {id: 2, name: 'Pop'}]

Below is the query to retrieve songs based on the artist using the artist id. I get a list of songs but if there are more than one artist on the song it only returns the artist whose id is passed to the sql query.

Something similar happens when trying to do the same for querying by a genre.

So my question is how do I return the data I want in the results but also perform a query on either the artist or genre? I will also have to get a count of total records for the total number of results the query would return.

SELECT ms.id, ms.title, ms.date_published, 
CONCAT('[', GROUP_CONCAT(DISTINCT(JSON_OBJECT('id', ma.id, 'name', ma.name, 'is_featuring', mas.is_featuring_artist)) ORDER BY mas.id separator ','), ']') AS artists, 
CONCAT('[', IF(mg.id IS NULL, '', GROUP_CONCAT(DISTINCT(JSON_OBJECT('id', mg.id, 'name', mg.name)) ORDER BY mg.name separator ',')), ']') AS genres 
FROM songs ms 
LEFT JOIN artist_song mas ON mas.song_id = ms.id 
LEFT JOIN artists ma ON ma.id = mas.artist_id 
LEFT JOIN genre_song mgs ON mgs.song_id = ms.id 
LEFT JOIN genres mg ON mg.id = mgs.genre_id 
WHERE ma.id = 2 AND ms.published = 1 
GROUP BY ms.id
ORDER BY ms.date_published DESC 
LIMIT 10  
OFFSET 0;

This is the result I would get back. Notice how the artist Pauli is no longer in the artists array as I query for an artist with the id of 2.

id title date_published artists genres
1 My Song 2022-01-01 15:00:01 [{id: 2, name: 'Tony', is_featuring: 1}] [{id: 1, name: 'Rock'}, {id: 2, name: 'Pop'}]

Below are the tables

Songs Table

id name published

Artists Table

id name

Artist Songs Table

id artist_id song_id is_featured

Genres Table

id name

Genre Songs Table

id genre_id song_id

You need to join with artist_song twice. One of them restricts the songs that are selected, the other is to get all the artists on the song.

SELECT ms.id, ms.title, ms.date_published, 
CONCAT('[', GROUP_CONCAT(DISTINCT(JSON_OBJECT('id', ma.id, 'name', ma.name, 'is_featuring', mas.is_featuring_artist)) ORDER BY mas.id separator ','), ']') AS artists, 
CONCAT('[', IF(mg.id IS NULL, '', GROUP_CONCAT(DISTINCT(JSON_OBJECT('id', mg.id, 'name', mg.name)) ORDER BY mg.name separator ',')), ']') AS genres 
FROM songs ms 
JOIN artist_song mas1 ON mas1.song_id = ms.id
JOIN artist_song mas ON mas.song_id = ms.id 
JOIN artists ma ON ma.id = mas.artist_id 
LEFT JOIN genre_song mgs ON mgs.song_id = ms.id 
LEFT JOIN genres mg ON mg.id = mgs.genre_id 
WHERE mas1.artist_id = 2 AND ms.published = 1 
GROUP BY ms.id
ORDER BY ms.date_published DESC 
LIMIT 10  
OFFSET 0;

There's no need to join with artists twice, since you're not using anything from that table when restricting. You can restrict the artist ID from mas1.artist_id .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM