Mysql
 sql >> Base de données >  >> RDS >> Mysql

LEFT JOIN après GROUP BY ?

Il y a eu de bonnes réponses jusqu'à présent, mais j'adopterais une méthode légèrement différente assez similaire à ce que vous avez décrit à l'origine

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

Dans ce cas, la sous-requête est chargée de rassembler les chansons avec des balises en une ligne par chanson. Ceci est ensuite joint à Votes par la suite. J'ai également choisi de résumer simplement la colonne v.votes comme vous l'avez indiqué, c'est 1 ou 0 et donc une somme (v.votes) ajoutera 1 + 1 + 1 + 0 + 0 =3 sur 5 sont des votes positifs, tandis que SUM(1-v.vote) additionnera 0+0+0+1+1 =2 sur 5 sont des votes négatifs.

Si vous aviez un index sur les votes avec les colonnes (id_song, vote), cet index serait utilisé pour cela afin qu'il n'atteigne même pas la table. De même, si vous aviez un index sur Songs_Tags avec (id_song,id_tag), cette table ne serait pas touchée par la requête.

modifier solution ajoutée en utilisant 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