9

我确定有一个合适的词我不记得了,但问题很容易描述:我有一个表 groupmembers,这是组和成员之间的简单关系:

id | groupid | memberid
1  | g1      | m1
2  | g1      | m2
3  | g2      | m1
4  | g2      | m2
5  | g2      | m3

上面描述了两组,一组是 m1 和 m2,一组是 m1、m2 和 m3。如果我想选择有成员 m1,m2 但没有其他成员的 groupids,我该怎么做?我尝试过的方法也会返回 g2,因为 m1 和 m2 是它们的子集。

更新:哇,一些很棒的答案!让我首先澄清一下我的问题——我希望能够选择与给定成员 m1 和 m2 完全匹配的组。因此,如果组还包含比 m1 和 m2 更多的成员,则它不应该匹配,如果组包含的成员少于 m1 和 m2,它也不应该匹配。

4

6 回答 6

10

从你的短语

我想选择有成员 m1,m2 但没有其他成员的 groupid

试试这个,背后的想法是count匹配条件和子句的记录的总实例,where并且它等于每组的记录总数。

SELECT groupid
FROM table1 a
WHERE memberid IN ('m1','m2')
GROUP BY groupid
HAVING COUNT(*) = 
(
  SELECT COUNT(*)
  FROM table1 b
  WHERE b.groupid = a.groupid
  GROUP BY b.groupID
)

SQLFiddle 演示

于 2012-10-08T06:14:38.493 回答
4

您正在寻找具有 m1 和 m2 的组与恰好具有两个成员的组之间的交集。SQL 有一个运算符:

select groupid
from group_table
where memberid in ('m1','m2')
group by groupid 
having count(distinct memberid) = 2
intersect
select groupid 
from group_table
group by groupid 
having count(distinct memberid) = 2

(如果您使用的是 Oracle,intersect则称为minus

这是一个 SQLFiddle 演示:http ://sqlfiddle.com/#!12/df94d/1

虽然我认为 John Woo 的解决方案在性能方面可能更有效。

于 2012-10-08T06:55:17.543 回答
2

此查询有问题

SELECT groupid
FROM table1 a
WHERE memberid IN ('m1','m2')
GROUP BY groupid
HAVING COUNT(*) = 
(
  SELECT COUNT(*)
  FROM table1 b
  WHERE b.groupid = a.groupid
  GROUP BY b.groupID
)

它将仅匹配具有 m1 或仅 m2 的组。为此,我们可以添加另一个计数检查

SELECT groupid
FROM table1 a
WHERE memberid IN ('m1','m2')
GROUP BY groupid
HAVING COUNT(*) = 2 --since we already know we should have exactly two rows
AND COUNT(*) = 
(
  SELECT COUNT(*)
  FROM table1 b
  WHERE b.groupid = a.groupid
  GROUP BY b.groupID
)
于 2013-07-09T16:12:33.157 回答
1
-- sample table for discussion
CREATE TABLE tbl
  (id int, groupid varchar(2), memberid varchar(2));
INSERT INTO tbl
  (id, groupid, memberid)
VALUES
    (6, 'g4', 'm1'),
    (7, 'g4', 'm2'),
    (8, 'g6', 'm1'),
    (9, 'g6', 'm3'),
    (1, 'g1', 'm1'),
    (2, 'g1', 'm2'),
    (3, 'g2', 'm1'),
    (4, 'g2', 'm2'),
    (5, 'g2', 'm3')
;

-- the query
select a.groupid, b.groupid peer
from (select groupid, count(*) member_count, min(memberid) x, max(memberid) y
      from tbl
      group by groupid) A
join
     (select groupid, count(*) member_count, min(memberid) x, max(memberid) y
      from tbl
      group by groupid) B
  on a.groupid<b.groupid and a.member_count=b.member_count and a.x=b.x and a.y=b.y
join tbl A1
  on A1.groupid = A.groupid
join tbl B1
  on B1.groupid = B.groupid and A1.memberid = B1.memberid
group by A.groupid, b.groupid, A.member_count
having count(1) = A.member_count;

-- the result
GROUPID PEER
g1  g4

上面显示了一种以groups高度优化的方式与同行一起列出的方法。通过将组分解为成员计数并采用最小值和最大值,它适用于大型数据库。使用直接连接可以快速减少组,并且仅对于剩余的匹配项,查询完整的表并重新加入组 id A 和 B 以确定它们是否是等效组。

如果您有 3 个相似的组 (101,103,104),这些组将显示为三个单独的行 (101,103),(101,104),(103,104) - 因为每一对都形成一个对等互连,因此如果您已经知道其中一个,最好使用这样的查询您要为其查找对等的组。此过滤器将适合第一个子查询。

于 2012-10-08T06:58:00.797 回答
1
SELECT DISTINCT                          -- if (groupid, memberid) is unique
                                         -- no need for the DISTINCT
    a.groupid
FROM 
    tableX AS a
  JOIN
    tableX AS b  
      ON b.groupid = a.groupid 
WHERE a.memberid = 'm1' 
  AND b.memberid = 'm2'
  AND NOT EXISTS
      ( SELECT *
        FROM tableX AS t
        WHERE t.groupid = a.groupid
          AND t.memberid NOT IN ('m1', 'm2') 
      ) ;
于 2012-10-08T07:02:39.743 回答
0
id | groupid | memberid
1  | g1      | m1
2  | g1      | m2
3  | g2      | m1
4  | g2      | m2
5  | g2      | m3

select GRPID from arcv where GRPID in (
select GRPID from arcv  
group by GRPID  having count(1)=2) and memberid in ('m1','m2')
于 2014-03-20T12:11:26.183 回答