2013-11-23 18 views
1

我试图让我的头绕着这个查询,但其中一个记录仍然不断弹出。总而言之,我的目的是向左侧展示群组成员,并从右侧的群组中包含而不是的电话簿中的姓名。这样用户可以选择它们并将它们添加到组中。MySQL:让所有的用户不是群组的一部分

user_id firstname group_id grpname 
------- --------- -------- ---------- 
     1 Luker    3 Abc  
     2 John    1 Some Group 
     3 Sam    2 Awesome Group 
     4 Mitch    1 Some Group 
     4 Mitch    2 Awesome Group 
     5 Rocky  (NULL) (NULL)  
     6 Pops   (NULL) (NULL) 

的唯一的事情是,如果一个用户是多个组(USER_ID 4)的一部分,他们的名字不应该在电话簿显示在所有因为它已经被放置在现有的名单成员。

-- Query for group_id 2 
SELECT user.id user_id, user.firstname, grp.id group_id, grp.grpname FROM agi_user user 
    LEFT JOIN agi_group_user gu ON user.id = gu.user_id 
    LEFT JOIN agi_groups grp ON gu.group_id = grp.id 
    WHERE grp.id IS NULL OR grp.id != 2 
    GROUP BY user.id 

但出于某种原因,用户米奇仍不断弹出。

user_id firstname group_id grpname 
------- --------- -------- ---------- 
     1 Luker    3 Abc  
     2 John    1 Some Group 
     4 Mitch    1 Some Group 
     5 Rocky  (NULL) (NULL)  
     6 Paps   (NULL) (NULL) 

编辑::我需要的输出是

user_id firstname group_id grpname 
------- --------- -------- ---------- 
     1 Luker    3 Abc  
     2 John    1 Some Group 
     5 Rocky  (NULL) (NULL)  
     6 Paps   (NULL) (NULL) 

基本上,我想所有的用户不是组包括NULL的一部分。但是因为一个用户是多个组的一部分,所以她的记录不应该出现,因为其他组可能具有3或4的group_id(或除2之外的其他任何组)。

回答

2

您可以使用NOT EXIST来检查是否有根本没有组/用户排第2组和给定的用户:

SELECT 
    user.id user_id, 
    user.firstname, 
    grp.id group_id, 
    grp.grpname 
FROM 
    agi_user user 
    LEFT JOIN agi_group_user gu ON user.id = gu.user_id 
    LEFT JOIN agi_groups grp ON gu.group_id = grp.id 
WHERE 
    NOT EXISTS (
    SELECT 'x' FROM agi_group_user x 
    WHERE 
     x.user_id = user.user_id and 
     x.group_id = 2) 
GROUP BY 
    user.id 

注意,如果用户不是在第2组,但有两个其他小组,他将在这个结果中出现1次,并且只有他所在的小组中的一个返回。要解决该问题,可以将grp.id添加到GROUP BY子句中,或者可以使用GROUP_CONCAT在单个字段中返回组名列表。

另外,这也应该工作,在MySQL中它甚至可以执行得更好,因为它吸引子查询。我个人认为它在语义上不太清楚发生了什么事情。 它再次加入用户/组表,但将group_id(2)添加到联接中。如果此表没有返回行,则用户不在组2中。有关GROUP_CONCAT的注释也适用于此查询。

SELECT 
    user.id user_id, 
    user.firstname, 
    grp.id group_id, 
    grp.grpname 
FROM 
    agi_user user 
    LEFT JOIN agi_group_user gu ON user.id = gu.user_id 
    LEFT JOIN agi_groups grp ON gu.group_id = grp.id 
    LEFT JOIN agi_group_user x ON user.id = x.user_id and x.group_id = 2 
WHERE 
    x.group_id IS NULL 
GROUP BY 
    user.id 
+0

这是完美的。你的第二个查询按计划进行,我从来没有想过要自行加入。谢谢! – enchance

2

如果我理解正确的,你想这样:

这就是所谓的反半连接(或只是反连接),并可以做到“不属于第2组的所有用户”用LEFT JOIN /IS NULL查询:

SELECT u.id user_id, u.firstname 
FROM agi_user AS u 
    LEFT JOIN agi_group_user AS gu 
     ON u.id = gu.user_id 
     AND gu.group_id = 2 
WHERE gu.group_id IS NULL ; 

或用NOT EXISTS子查询:

SELECT u.id user_id, u.firstname 
FROM agi_user AS u 
WHERE NOT EXISTS 
     (SELECT 1 
     FROM JOIN agi_group_user AS gu 
     WHERE u.id = gu.user_id 
      AND gu.group_id = 2 
    ) ; 
+0

你的第一个查询工作!但是,在“LEFT JOIN”之后,你是如何使用'AND'的?我的印象是使用'AND'仅用于'WHERE'。这对我来说是新的,你能告诉我如何为每个用户输出'group_id'和'group_name',就像我原来的查询一样?我似乎无法做到。 – enchance

+0

你为什么想要'group_id'和'group_name'?如果用户有多个组(但他不在第2组)?应该显示哪一个? –

+0

只是好奇。但你不需要担心。 – enchance

相关问题