我正在尝试检查数据库是否存在特定组合。
表:conversations
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+----+
表:conversations_users
+----+--------------+------+
| id | conversation | user |
+----+--------------+------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 1 |
| 4 | 2 | 2 |
| 5 | 2 | 3 |
| 6 | 2 | 4 |
| 7 | 3 | 2 |
| 8 | 3 | 3 |
| 9 | 4 | 2 |
| 10 | 4 | 4 |
+----+--------------+------+
然后我想进行查询以获得这些用户在同一对话中的对话:
Users: 1,2,3,4 (Only them, no else)
如果只有对话的对话,我想获得该对话的ID,否则result
应该成为0
任何人都有任何想法如何做到这一点?
答案 0 :(得分:3)
这个想法是计算给定对话中的不同用户。如果它与您在IN
子句中设置的用户数相匹配,那么您确定只有您搜索的用户数:
SELECT id
FROM conversations_users
WHERE user in (1, 2, 3, 4)
GROUP BY id
HAVING COUNT(DISTINCT user) = 4
请注意,这不会输出4个用户中只有3个出现的对话。如果您也需要这些对话,那么:
SELECT id
FROM conversations_users
WHERE user in (1, 2, 3, 4)
GROUP BY id
HAVING COUNT(DISTINCT user) <= 4
答案 1 :(得分:2)
SELECT
cs.conversation,
IF(csl.total = 4,'yes','no') AS AllIn
FROM conversations_users AS cs
LEFT JOIN (
SELECT
conversation ,
COUNT(DISTINCT user) AS total
FROM conversations_users
WHERE user IN (1,2,3,4)
GROUP BY conversation
) AS csl
ON csl.conversation = cs.conversation
GROUP BY cs.conversation
输出
| CONVERSATION | ALLIN |
------------------------
| 1 | no |
| 2 | yes |
| 3 | no |
| 4 | no |
这将为您提供所有会话ID及其状态
| CONVERSATION | ALLIN |
------------------------
| 1 | 0 |
| 2 | 2 |
| 3 | 0 |
| 4 | 0 |
答案 2 :(得分:2)
我认为这就是你要找的东西:
SELECT cu.conversation
FROM (select conversation, count(distinct user) usercnt
from conversations_users
group by conversation) t
JOIN conversations_users cu on t.conversation = cu.conversation
WHERE cu.user in (1, 2, 3, 4) AND t.usercnt = 4
GROUP BY cu.conversation
HAVING COUNT(DISTINCT cu.user) = 4
这使用子查询来确定与每个对话关联的用户总数。这需要确保您在对话中没有比1,2,3和4更多的用户。
答案 3 :(得分:2)
如果我理解你的问题,可以使用:
SELECT
conversation
FROM
conversations_users
GROUP BY
conversation
HAVING
COUNT(
DISTINCT CASE WHEN user IN (1,2,3,4) THEN user END
)=4 AND
COUNT(DISTINCT user)=4
答案 4 :(得分:2)
假设您还有一个users
表:
SELECT id
FROM conversations AS c
WHERE NOT EXISTS
( SELECT *
FROM users AS u
WHERE u.id IN (1, 2, 3, 4)
AND NOT EXISTS
( SELECT *
FROM conversations_users AS cu
WHERE cu.user = u.id
AND cu.conversation = c.id
)
)
AND NOT EXISTS
( SELECT *
FROM conversations_users AS co -- and only them
WHERE co.conversation = c.id
AND co.user NOT IN (1, 2, 3, 4)
) ;
如果您没有users
表或者您不想使用它(无论如何都可以看到原因),您可以替换此部分:
WHERE NOT EXISTS
( SELECT *
FROM users AS u
WHERE u.id IN (1, 2, 3, 4)
AND NOT EXISTS
使用:
WHERE NOT EXISTS
( SELECT *
FROM (SELECT 1 AS id UNION SELECT 2 UNION
SELECT 3 UNION SELECT 4) AS u
WHERE NOT EXISTS
上面的查询,虽然一般在MySQL中不会非常有效(归咎于双嵌套和天真的优化器)。 GROUP BY / COUNT
方式可能更有效 - 但请使用您的数据进行测试。在这个答案中,您还可以找到更多方法(超过10种)来回答这类问题: How to filter SQL results in a has-many-through relation 其中一些方法在MySQL中不起作用,但很多方法都可以。我希望MySQL中的查询5和6非常有效(通过查询比组更有效)。
你的情况有所不同,你想要确切的关系划分,而那个问题/答案是关于(简单的)关系划分,所以你可以像这样写5:
SELECT id
FROM conversations AS c
WHERE EXISTS (SELECT * FROM conversations_users AS cu
WHERE cu.conversation = c.id AND cu.user = 1)
AND EXISTS (SELECT * FROM conversations_users AS cu
WHERE cu.conversation = c.id AND cu.user = 2)
AND EXISTS (SELECT * FROM conversations_users AS cu
WHERE cu.conversation = c.id AND cu.user = 3)
AND EXISTS (SELECT * FROM conversations_users AS cu
WHERE cu.conversation = c.id AND cu.user = 4)
AND NOT EXISTS (SELECT * FROM conversations_users AS cu
WHERE cu.conversation = c.id AND cu.user NOT IN (1,2,3,4))
答案 5 :(得分:2)
保持查询和连接简单易读。
由于用户5的存在,我假设你不要求所有4个用户(1,2,3,4)都在你正在寻找的对话中,而是任何对话仅包括这4个用户的任意组合。
<强> DEMO 强>
select distinct
cu.conversation
from
conversations_users cu
left join
conversations_users cu2 ON cu.conversation = cu2.conversation
where
cu.user in (1 , 2, 3, 4)
and cu2.user in (1 , 2, 3, 4)
and cu.user != cu2.user /* include this clause if you need to exclude conversations of a user with themselves */
如果您想要只涉及所有4位用户的对话,请告诉我。
您要删除其他会话吗?当你说“结果应该变为0”时,你指的是对话ID的行数或值?如果是后者则使用:
select distinct
case
when
cu.user in (1 , 2, 3, 4)
and cu2.user in (1 , 2, 3, 4)
then
cu.conversation
else 0
end conversation
from
conversations_users cu
left join
conversations_users cu2 ON cu.conversation = cu2.conversation
where
1 = 1
and cu.user != cu2.user /* include this clause if you need to exclude conversations of a user with themselves */
答案 6 :(得分:2)
SELECT ID FROM CONVERSATIONS WHERE ID IN
(SELECT CONVERSATIONS FROM CONVERSATION_USERS
GROUP BY CONVERSATIONS HAVING COUNT(DISTINCT USER) >= 2)
答案 7 :(得分:2)
这是“set-within-sets”查询的示例。对于这些,我喜欢将group by
与having
子句一起使用:
select conversation
from conversation_users cu
group by conversation
having SUM(user = 1) > 0 and
sum(user = 2) > 0 and
sum(user = 3) > 0 and
sum(user = 4) > 0 and
sum(user not in (1, 2, 3, 4)) = 0
having子句的每个条件对应于问题中指定的五个条件之一:
答案 8 :(得分:2)
如果我正确地阅读了您的要求,您需要一个任何对话的ID,其中唯一的人是(例如)1,2,3和4,并且所有这些人都在其中。如果不是,你想要0返回该对话。
如果是这样那么
SELECT CASE WHEN MatchCount = 4 AND UnMatchCount IS NULL THEN conversations.id ELSE 0 END
FROM conversations
LEFT OUTER JOIN (SELECT conversation, COUNT(DISTINCT user) AS MatchCount FROM conversations_users WHERE user IN (1,2,3,4) GROUP BY conversation) Sub1 ON conversations.id = Sub1.conversation
LEFT OUTER JOIN (SELECT conversation, COUNT(DISTINCT user) AS UnMatchCount FROM conversations_users WHERE user NOT IN (1,2,3,4) GROUP BY conversation) Sub2 ON conversations.id = Sub2.conversation
编辑 - 上述查询的修改版本仅返回仅涉及4个用户的会话ID。玩这个似乎是一种非常有效的方式。
SELECT conversations.id
FROM conversations
LEFT OUTER JOIN (SELECT conversation, COUNT(DISTINCT user) AS MatchCount FROM conversations_users WHERE user IN (1,2,3,4) GROUP BY conversation) Sub1 ON conversations.id = Sub1.conversation
LEFT OUTER JOIN (SELECT conversation, COUNT(DISTINCT user) AS UnMatchCount FROM conversations_users WHERE user NOT IN (1,2,3,4) GROUP BY conversation) Sub2 ON conversations.id = Sub2.conversation
WHERE MatchCount = 4
AND UnMatchCount IS NULL