如何查询特征table(AND条件)的多对多关系
How to query many-to-many relation with features table (AND condition)
我想这是一个常见的设置,但由于我没有做那么多 SQL 工作,所以我无法理解这个......所以,我有一堆具有某些特征(音乐风格、情绪等)的歌曲,我想 select 具有这些特征的歌曲(例如快乐和欣快的歌曲)。
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 |
+---------+------------+
我想 select 所有具有 AND
条件的特定功能的歌曲。我会将此查询用于 OR
-案例。
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;
但这显然不适用于 AND
条件,所以我想我走错路了...任何提示将不胜感激。
如果过滤连接的结果集并在 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
参见demo。
结果:
> id | title
> -: | :------
> 2 | song #2
我想这是一个常见的设置,但由于我没有做那么多 SQL 工作,所以我无法理解这个......所以,我有一堆具有某些特征(音乐风格、情绪等)的歌曲,我想 select 具有这些特征的歌曲(例如快乐和欣快的歌曲)。
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 |
+---------+------------+
我想 select 所有具有 AND
条件的特定功能的歌曲。我会将此查询用于 OR
-案例。
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;
但这显然不适用于 AND
条件,所以我想我走错路了...任何提示将不胜感激。
如果过滤连接的结果集并在 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
参见demo。
结果:
> id | title
> -: | :------
> 2 | song #2