Đã có một số câu trả lời hay cho đến nay, nhưng tôi sẽ áp dụng một phương pháp hơi khác khá giống với những gì bạn đã mô tả ban đầu
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
Trong đó, truy vấn con chịu trách nhiệm đối chiếu các bài hát với các thẻ thành 1 hàng trên cơ sở bài hát. Điều này sau đó được tham gia vào Phiếu bầu sau đó. Tôi cũng đã chọn chỉ đơn giản là tổng hợp cột v.votes như bạn đã chỉ ra là 1 hoặc 0 và do đó một SUM (v.votes) sẽ cộng lại 1 + 1 + 1 + 0 + 0 =3 trong số 5 là phiếu tán thành, trong khi SUM (1-v.vote) sẽ tổng 0 + 0 + 0 + 1 + 1 =2 trong số 5 là phiếu phản đối.
Nếu bạn có một chỉ mục về phiếu bầu với các cột (id_song, phiếu bầu) thì chỉ mục đó sẽ được sử dụng cho mục đích này để nó thậm chí không đạt được bảng. Tương tự như vậy nếu bạn có một chỉ mục trên Songs_Tags với (id_song, id_tag) thì bảng đó sẽ không bị truy vấn truy cập.
chỉnh sửa giải pháp đã thêm bằng cách sử dụng số lượng
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