开发者

SQL SELECT with m:n relationship

I have m:n 开发者_Python百科relationship between users and tags. One user can have m tags, and one tag can belong to n users. Tables look something like this:

USER:
ID
USER_NAME

USER_HAS_TAG:
USER_ID
TAG_ID

TAG:
ID
TAG_NAME

Let's say that I need to select all users, who have tags "apple", "orange" AND "banana". What would be the most effective way to accomplish this using SQL (MySQL DB)?


SELECT  u.*
FROM    (
        SELECT  user_id
        FROM    tag t
        JOIN    user_has_tag uht
        ON      uht.tag_id = t.id
        WHERE   tag_name IN ('apple', 'orange', 'banana')
        GROUP BY
                user_id
        HAVING  COUNT(*) = 3
        ) q
JOIN    user u
ON      u.id = q.user_id

By removing HAVING COUNT(*), you get OR instead of AND (though it will not be the most efficient way)

By replacing 3 with 2, you get users that have exactly two of three tags defined.

By replacing = 3 with >= 2, you get users that have at least two of three tags defined.


In addition to the other good answers, it's also possible to check the condition in a WHERE clause:

select *
from user u
where 3 = (
    select count(distinct t.id)
    from user_has_tag uht
    inner join tag t on t.id = uht.tag_id
    where t.name in ('apple', 'orange', 'banana') 
    and uht.user_id = u.userid
)

The count(distinct ...) makes sure a tag is counted only once, even if the user has multiple 'banana' tags.

By the way, the site fruitoverflow.com is not yet registered :)


You can do it all with joins...

select u.*
from user u

inner join user_has_tag ut1 on u.id = ut1.user_id 
inner join tag t1 on ut1.tag_id = t1.id and t1.tag_name = 'apple'

inner join user_has_tag ut2 on u.id = ut2.user_id 
inner join tag t2 on ut2.tag_id = t2.id and t2.tag_name = 'orange'

inner join user_has_tag ut3 on u.id = ut3.user_id 
inner join tag t3 on ut3.tag_id = t3.id and t3.tag_name = 'banana'


SELECT *
FROM USER u
INNER JOIN USER_HAS_TAG uht
ON u.id = uht.user_id
INNER JOIN TAG t
ON uht.TAG_ID = t.ID
WHERE t.TAG_NAME IN ('apple','orange','banana')
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜