Bisher gab es einige gute Antworten, aber ich würde eine etwas andere Methode anwenden, die der von Ihnen ursprünglich beschriebenen ziemlich ähnlich ist
SELECT
songsWithTags.*,
COALESCE(SUM(v.vote),0) AS votesUp,
COALESCE(SUM(1-v.vote),0) AS votesDown
FROM (
SELECT
s.*,
COLLATE(GROUP_CONCAT(st.id_tag),'') AS tags_ids
FROM Songs s
LEFT JOIN Songs_Tags st
ON st.id_song = s.id
GROUP BY s.id
) AS songsWithTags
LEFT JOIN Votes v
ON songsWithTags.id = v.id_song
GROUP BY songsWithTags.id DESC
Dabei ist die Unterabfrage dafür verantwortlich, Songs mit Tags in einer Basis von 1 Zeile pro Song zu sortieren. Dies wird dann später mit Votes verbunden. Ich habe mich auch dafür entschieden, die v.votes-Spalte einfach zusammenzufassen, da Sie angegeben haben, dass sie 1 oder 0 ist, und daher ergibt eine SUM(v.votes) 1 + 1 + 1 + 0 + 0 =3 von 5 sind positive Stimmen. während SUM(1-v.vote) 0+0+0+1+1 summiert =2 von 5 sind Downvotes.
Wenn Sie einen Index für Stimmen mit den Spalten (id_song,vote) hätten, würde dieser Index dafür verwendet, sodass er nicht einmal in die Tabelle eindringt. Wenn Sie einen Index für Songs_Tags mit (id_song,id_tag) hätten, würde diese Tabelle von der Abfrage nicht getroffen.
bearbeiten hinzugefügte Lösung mit count
SELECT
songsWithTags.*,
COUNT(CASE WHEN v.vote=1 THEN 1 END) as votesUp,
COUNT(CASE WHEN v.vote=0 THEN 1 END) as votesDown
FROM (
SELECT
s.*,
COLLATE(GROUP_CONCAT(st.id_tag),'') AS tags_ids
FROM Songs s
LEFT JOIN Songs_Tags st
ON st.id_song = s.id
GROUP BY s.id
) AS songsWithTags
LEFT JOIN Votes v
ON songsWithTags.id = v.id_song
GROUP BY songsWithTags.id DESC