【问题标题】:Using 'AND' in a many-to-many relationship在多对多关系中使用“AND”
【发布时间】:2013-03-26 00:29:54
【问题描述】:

我有一个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”中的用户。

最有效的方法是什么?

【问题讨论】:

    标签: sql sql-server sql-server-2008 tsql select


    【解决方案1】:

    这个问题通常被称为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
    

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

    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  ║
    ╚══════╝
    

    【讨论】:

    • 非常感谢,这很有帮助。另外,我现在有一个名字,为它做一些研究。再次感谢。
    • 不接受这个答案的原因是什么?无论如何,您想了解更多信息,以便我改进答案。
    • 抱歉,非常感谢您的回复,但我认为您没有完全回答我的问题。我的问题是我想在 TypeId 列不同时使用 AND,但在相同时使用 OR。所以...我希望所有用户都在“Directors”或“IT”和“London”中。
    • 另外,在你的 SQLFiddle 中,你似乎加入了 Group 的 TypeId 列,而不是它的 Id 列。 TypeId 是一个鉴别器字段。这是我目前正在玩的小提琴:sqlfiddle.com/#!3/918cc/5
    • 确实有效。唯一的缺点是查询可以是任意数量的组,所以我并不总是知道要检查每种类型的 COUNT。我将拥有的只是一组组 ID。这看起来怎么样? sqlfiddle.com/#!3/987be/8
    【解决方案2】:

    我得到了以下解决方案(在 J W 和 this article 的帮助下):

    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 都有一个额外的连接。执行计划看起来很相似,所以我选择了第一个选项。

    【讨论】:

      猜你喜欢
      • 2021-02-18
      • 2021-02-25
      • 1970-01-01
      • 1970-01-01
      • 2019-02-16
      • 2017-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多