根据多对多关系

时间:2015-08-21 10:54:46

标签: mysql sql many-to-many

我有一个简单的线程即时消息系统,它是根据以下架构构建的:

Schema

一个线程可以包含两个或更多用户,用户可以属于多个线程。当用户尝试创建新线程时,我需要检查用户之间是否已存在现有线程(由ID指定),并返回现有线程。如果我指定的用户是该线程中的用户,我应该只返回现有的线程。

通常情况下,我会使用这样的查询:

select distinct t.* from threads t
inner join thread_users tu on tu.thread_id = t.id
where tu.user_id in (1, 2);

但是,此查询将返回两个用户(ID 12)不是该线程中用户的线程。我真正需要的是像only in (1, 2)条款。

如何实现与where only in子句相同的功能?

编辑:在我发布后,在侧边栏中出现的相关问题提出了这个问题:

select t.* from threads t
inner join thread_users tu on tu.thread_id = t.id
where tu.user_id in (1, 2)
having count(distinct tu.user_id) = 2;

这个似乎可以工作,但我可能会错过一个我在数据库数据中没有考虑到的边缘情况?

2 个答案:

答案 0 :(得分:2)

这是一个set-within-a set子查询的示例:您正在寻找一个线程内的用户组。我喜欢使用group byhaving解决这些问题,因为这是一种非常灵活的方法。我认为以下是您想要的:

select t.*
from threads t join
     thread_users tu
     on t.id = tu.thread_id
group by t.id
having sum(tu.user_id = 1) > 0 and
       sum(tu.user_id = 2) > 0 and
       sum(tu.user_id not in (1, 2)) = 0;

答案 1 :(得分:0)

此查询将为您提供包含用户12且仅包含这些用户的线索提示:

SELECT t.id
FROM threads t join
     thread_users tu
     on t.id = tu.thread_id
GROUP by t.id
HAVING COUNT(distinct user_id) = 2
    AND SUM (CASE WHEN user_id NOT IN (1, 2) THEN 1 ELSE 0 END) = 0