查找一列中具有相同值的行和另一列中的其他值?

Ray*_*Ray 5 sql postgresql relational-division

我有一个PostgreSQL数据库,用于将用户存储在users表中,并将对话存储在conversation表中.由于每个用户都可以参与多个对话,并且每个对话都可能涉及多个用户,因此我有一个conversation_user链接表来跟踪哪些用户参与每个对话:

# conversation_user
id  |  conversation_id | user_id
----+------------------+--------
1   |                1 |      32
2   |                1 |       3
3   |                2 |      32
4   |                2 |       3
5   |                2 |       4
Run Code Online (Sandbox Code Playgroud)

在上表中,用户32只与用户3进行一次对话,另一次与3和用户4进行对话.如何编写一个查询,表明只有用户32和用户3之间有对话?

我尝试过以下方法:

SELECT conversation_id AS cid,
       user_id
FROM conversation_user
GROUP BY cid HAVING count(*) = 2
AND (user_id = 32
     OR user_id = 3);

SELECT conversation_id AS cid,
   user_id
FROM conversation_user
GROUP BY (cid HAVING count(*) = 2
AND (user_id = 32
     OR user_id = 3));

SELECT conversation_id AS cid,
       user_id
FROM conversation_user
WHERE (user_id = 32)
  OR (user_id = 3)
GROUP BY cid HAVING count(*) = 2;
Run Code Online (Sandbox Code Playgroud)

这些查询会抛出一个错误,指出user_id必须出现在GROUP BY子句中或用于聚合函数.将它们置于聚合函数(例如MINMAX)中听起来不合适.我认为我的前两次尝试是将它们放入GROUP BY条款中.

我究竟做错了什么?

Erw*_*ter 4

这是关系划分的情况。我们在这个相关问题下收集了一系列技术:

特殊的困难是排除额外的用户。基本上有4种技术。

我建议LEFT JOIN/ IS NULL

SELECT cu1.conversation_id
FROM        conversation_user cu1
JOIN        conversation_user cu2 USING (conversation_id)
LEFT   JOIN conversation_user cu3 ON cu3.conversation_id = cu1.conversation_id
                                 AND cu3.user_id NOT IN (3,32)
WHERE  cu1.user_id = 32
AND    cu2.user_id = 3
AND    cu3.conversation_id IS NULL;
Run Code Online (Sandbox Code Playgroud)

或者NOT EXISTS

SELECT cu1.conversation_id
FROM   conversation_user cu1
JOIN   conversation_user cu2 USING (conversation_id)
WHERE  cu1.user_id = 32
AND    cu2.user_id = 3
AND NOT EXISTS (
   SELECT 1
   FROM   conversation_user cu3
   WHERE  cu3.conversation_id = cu1.conversation_id
   AND    cu3.user_id NOT IN (3,32)
   );
Run Code Online (Sandbox Code Playgroud)

这两个查询都不依赖于 的UNIQUE约束(conversation_id, user_id),该约束可能存在也可能不存在。user_id这意味着,如果同一对话多次列出 32(或 3),则查询甚至可以工作。但是,您在结果中得到重复的行,并且需要应用DISTINCTor GROUP BY
唯一的条件是您制定的条件:

...显示只有用户 32 和用户 3 之间存在对话的查询?

审核查询

您在评论中链接的查询将不起作用。您忘记排除其他参与者。应该是这样的:

SELECT *  -- or whatever you want to return
FROM   conversation_user cu1
WHERE  cu1.user_id = 32
AND    EXISTS (
   SELECT 1
   FROM   conversation_user cu2
   WHERE  cu2.conversation_id = cu1.conversation_id 
   AND    cu2.user_id = 3
   )
AND NOT EXISTS (
   SELECT 1
   FROM   conversation_user cu3
   WHERE  cu3.conversation_id = cu1.conversation_id
   AND    cu3.user_id NOT IN (3,32)
   );
Run Code Online (Sandbox Code Playgroud)

user_id = 3这与其他两个查询类似,只是如果多次链接,它不会返回多行。