2 votes

Comment interroger une relation many-to-many avec une table de caractéristiques (condition AND) ?

Je suppose qu'il s'agit d'un paramètre courant, mais comme je ne travaille pas beaucoup en SQL, je n'arrive pas à m'y retrouver... Donc, j'ai un tas de chansons qui ont certaines caractéristiques (style de musique, humeur, etc.) et je voudrais sélectionner les chansons qui sont attribuées à certaines de ces caractéristiques (par exemple, les chansons qui sont heureuses et euphoriques).

SONG
+----+----------+
| id |    title |
+----+----------+
|  1 |  song #1 |
+----+----------+
|  2 |  song #2 |
+----+----------+

FEATURE
+----+-------+----------+
| id |  name |    value |
+----+-------+----------+
|  1 |  mood |      sad |
+----+-------+----------+
|  2 |  mood |    happy |
+----+-------+----------+
|  3 |  mood | euphoric |
+----+-------+----------+
|  4 | style |     rock |
+----+-------+----------+
|  5 | style |     jazz |
+----+-------+----------+

SONG_FEATURE
+---------+------------+
| song_id | feature_id |
+---------+------------+
|       1 |          1 |
+---------+------------+
|       2 |          1 |
+---------+------------+
|       2 |          2 |
+---------+------------+

Je voudrais sélectionner toutes les chansons qui ont certaines caractéristiques avec une AND condition. J'utiliserais cette requête pour la OR -valises.

SELECT 
    s.*,
    f.*
FROM
    song_feature sf
        LEFT JOIN song s ON s.id = sf.song_id
        LEFT JOIN feature f ON f.id = sf.feature_id
WHERE
    (
        f.name = 'style'
        AND f.value = 'pop'
    )
    OR /* <-- this works, but I would like an AND condition */
    (
        f.name = 'style'
        AND f.value = 'pop'
    )
GROUP BY sf.song_id;

Mais cela ne fonctionne évidemment pas pour le AND condition, donc je suppose que je suis sur la mauvaise voie ici... Tout conseil sera grandement apprécié.

2voto

forpas Points 116974

Vous pouvez le faire avec l'agrégation, si vous filtrez le jeu de résultats des jointures et définissez la condition dans la clause HAVING :

SELECT s.id, s.title
FROM SONG s
INNER JOIN SONG_FEATURE sf ON sf.song_id = s.id
INNER JOIN FEATURE f ON f.id = sf.feature_id
WHERE (f.name, f.value) IN (('mood', 'sad'), ('mood', 'happy'))
GROUP BY s.id, s.title
HAVING COUNT(DISTINCT f.name, f.value) = 2

Voir le Démonstration .
Résultats :

> id | title  
> -: | :------
>  2 | song #2

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X