连接元素应该* all *符合某些条件

时间:2013-11-19 23:36:38

标签: sql postgresql relational-division sql-match-all

我的设置如下:

conversations(id) 

notifications(id, conversation_id, user_id)

users(id)

如果对话涉及某人,则user会与conversationnotification相关联。

目标:我正在寻找conversations关于给定ID的完全 users。{/ p>


显而易见:

SELECT DISTINCT conversations.* 
FROM "conversations" 
INNER JOIN "notifications" ON "notifications"."conversation_id" = "conversations"."id"
WHERE notifications.user_id IN (1, 2)

不起作用,因为它还会检索有关以下内容的对话:

  • ID为1,2和3的用户
  • ID为1和4的用户
  • ID为2和4的用户

这是不可取的。

2 个答案:

答案 0 :(得分:1)

这假设每个用户只能一次加入对话:

SELECT c.*
FROM   conversations c
JOIN   notifications n1 ON n1.conversation_id = c.id
JOIN   notifications n2 ON n2.conversation_id = c.id
WHERE  n1.user_id = 1
AND    n2.user_id = 2
AND    NOT EXISTS (
   SELECT 1
   FROM   notifications n3
   WHERE  n3.conversation_id = c.id
   AND    n3.user_id <> ALL ('{1,2}')
  )

这是关系师的一个特例。在这个相关的问题下,我们已经汇集了一整套技术: How to filter SQL results in a has-many-through relation

特殊要求是排除其他匹配。为此,我使用NOT EXISTS。您还可以使用LEFT JOIN / IS NULLNOT IN。更多细节:
Select rows which are not present in other table

同一用户可能会有多个通知

为避免结果中出现重复的对话,除上述内容外,您还可以使用DISTINCTGROUP BY。或者你开始抑制重复(可能更快):

SELECT c.*
FROM   conversations c
WHERE  EXISTS (
   SELECT 1
   FROM   notifications n1
   JOIN   notifications n2 USING (conversation_id)
   WHERE  n1.conversation_id = c.id
   AND    n1.user_id = 1
   AND    n2.user_id = 2
  )
AND    NOT EXISTS (
   SELECT 1
   FROM   notifications n3
   WHERE  n3.conversation_id = c.id
   AND    n3.user_id <> ALL ('{1,2}')
  )

答案 1 :(得分:1)

SELECT DISTINCT conversations.* 
FROM conversations c
    JOIN notifications n1 ON n1.conversation_id = c.id
    JOIN notifications n2 ON n2.conversation_id = n1.conversation_id AND n1.id <> n2.id
WHERE n1.user_id = 1 AND n2.User_Id =2 

我认为问题要求User_Id = 1和User_Id = 2之间的对话...... 如果除了1和2之外的任何人都不应该参与对话,那么Eric的回答就是你所需要的。