-1

我有一张Users桌子和一张Groups桌子。用户可以通过“UserInGroup”表在多个组中,组可以有一个“GroupTypeId”。

[User]
--------------
Id | Name
1  | Bob
2  | James

[UserInGroup]
-----------------
UserId | GroupId
1        1
1        2

[Group]
Id | Name      | TypeId
------------------------
1  | Directors | 1
2  | IT        | 1
3  | London    | 2

我想创建一个查询以返回例如同时位于“Directors”和“London”(而不是“Directors”或“London”)的用户。但是,我只想 AND 不同“类型”的组,我想 OR 相同类型的组。我可以为每个组类型创建一个单独的表,但我不能,因为它们是动态创建的。

理想情况下,我希望能够查询“Directors”或“IT”和“London”中的用户。

这样做最有效的方法是什么?

4

2 回答 2

3

这个问题通常被称为Relational Division.

SELECT  a.Name
FROM    [user] a
        INNER JOIN UserInGroup b
            ON a.ID = b.UserID
        INNER JOIN [Group] c
            ON b.groupID = c.TypeId
WHERE   c.Name IN ('Directors','London')
GROUP   BY a.Name
HAVING  COUNT(*) = 2

但是,如果没有对UNIQUEeach 强制执行约束,则需要使用关键字来过滤掉唯一组:GROUPUSERDISTINCT

SELECT  a.Name
FROM    [user] a
        INNER JOIN UserInGroup b
            ON a.ID = b.UserID
        INNER JOIN [Group] c
            ON b.groupID = c.TypeId
WHERE   c.Name IN ('Directors','London')
GROUP   BY a.Name
HAVING  COUNT(DISTINCT c.Name) = 2

两个查询的输出

╔══════╗
║ NAME ║
╠══════╣
║ Bob  ║
╚══════╝
于 2013-03-26T00:34:01.307 回答
0

我得出了以下解决方案(在 JW 和本文的帮助下):

SELECT  
  u.Name UserName
FROM [User] u
INNER JOIN [UserInGroup] uig
  ON uig.UserId = u.Id
INNER JOIN [Group] g
  ON g.Id = uig.GroupId
WHERE 
  g.Id IN (1,2,3) -- these are the passed in groupids
GROUP BY 
  u.Name
having count(distinct g.TypeId)
  = (select count(distinct g1.TypeId) 
     from [group] g1 where g1.Id IN (1,2,3))

这使我可以通过鉴别器字段对关系划分进行分组。另一种选择是:

SELECT  a.Name
FROM    [User] a
    INNER JOIN
    (
      SELECT  b.UserID
      FROM    UserInGroup b
              INNER JOIN [Group] c
                  ON b.groupID = c.Id
      WHERE   c.Name IN ('Directors','IT')
      GROUP   BY b.UserID
      HAVING  COUNT(DISTINCT c.Name) >= 1
    ) b ON a.ID = b.UserID
    INNER JOIN
    (
      SELECT  DISTINCT b.UserID
      FROM    UserInGroup b
              INNER JOIN [Group] c
                  ON b.groupID = c.Id
      WHERE   c.Name = 'London'
    ) c ON a.ID = c.UserID

每个 GroupTypeId 都有一个额外的连接。执行计划看起来很相似,所以我选择了第一个选项。

于 2013-03-27T09:16:23.327 回答