MySQL:让所有用户不属于某个组

时间:2013-11-23 15:38:15

标签: php 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

但出于某种原因,用户 Mitch 仍然不断弹出。

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。但是由于一个用户是多个组的一部分,因此她的记录仍然会出现,因为其他组可能有一个group_id为3或4(或除了2之外的任何其他组)。

2 个答案:

答案 0 :(得分:3)

您可以使用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

答案 1 :(得分:3)

如果我理解正确,您需要这样:“所有不属于第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
      ) ;