【问题标题】:Recursive select递归选择
【发布时间】:2012-08-28 16:51:34
【问题描述】:

我尝试使用WITH 创建一个 SQL 语句,但我做错了。

我得到了以下表格;

组(ID、名称)

1, 'My app'
2, 'Local admins'
3, 'Global admins'

用户(1,姓名)

1, 'Arne'

GroupOwners(GroupId、OwnerType、OwnerId)

1, 'Group', 2

GroupMembers(GroupId、MemberType、MemberId)

2, 'Group', 3
3, 'User', 1

我正在尝试查找Arne 拥有的所有组。在这种情况下,它是My App。但问题是Local Admins 被设置为所有者。而Global adminsLocal admins 的成员。而Arne 终于成为Global admins 的成员了。

别管钻石了,它们是不正确的

嵌套因组而异。 (有些用户直接在 GroupOwners 中,而另一些则可能有一个用户作为成员的组)

是否可以用一个母亲的 SQL 语句来解决?附加约束:Groups/Users 在系统的其他地方使用。

【问题讨论】:

  • 您需要为我们提供更好的数据库示例 ERD。您似乎在图表中将数据库实体与特定行(Arne 和 MyApp)混合在一起,使事情变得混乱。
  • 不是ERD,而是说明不同对象之间的关系。将其与列出的表格及其值一起使用。或:Group -> GroupOwners -> GroupMembers -> User。可能是Group -> GroupOwners -> GroupMembers -> GroupMembers -> UserGroup -> GroupOwners -> User。总是一步通过 GroupOwner 和 0..* 一步通过 groupMembers

标签: sql-server database-design


【解决方案1】:

这是递归 cte,它将首先找到组 Arno 的成员,然后匹配所有直接或间接包含这些组的组。结果最终加入到 GroupOwners 以限制结果。注意:如果Arno 可能是组的所有者,但不是组的成员,则此查询也需要 UNION 来附加这些组。

declare @UserID int = 1

; with allTheGroups as (
  select gm.GroupID
    from GroupMembers gm
   where gm.MemberType = 'User'
     and gm.MemberID = @UserID
  union all
  select gm.GroupID
    from GroupMembers gm
   inner join allTheGroups
      on gm.MemberID = allTheGroups.GroupID
   where gm.MemberType = 'Group'
)
select Groups.*
  from Groups
 inner join GroupOwners gow
    on Groups.ID = gow.GroupID
   and gow.OwnerType = 'Group'
 inner join allTheGroups a
    on gow.OwnerID = a.GroupID

Sql Fiddle with example is here.

用于检索直接拥有已添加组的用户的联合示例。需要附加到上面的查询中(当然,还要调整选择列表)。

union
select gow.OwnerID, Users.Name
  from GroupOwners gow
 inner join Users
    on gow.OwnerID = Users.ID
   and gow.OwnerType = 'User'
 where gow.OwnerID = @UserID

【讨论】:

  • Arne 是 Global Admins 的成员(最后一组成员行),而不是直接所有者。
  • 我必须首先查找每个组的所有所有者(单选)。然后遍历所有属于组的所有者,直到我找到“arne”作为链下的成员。
  • @jgauffin 我正在尝试不同的方法,从 Arne 的成员资格开始,以避免需要扁平化整个结构。希望我能找到路。
  • @jgauffin 请看看我修改后的答案。
  • 干得好,谢谢。现在我只需要尝试理解它 =)
【解决方案2】:

是的,您的表格建模不正确。你只需要有两张桌子。组和管理员(或用户,取决于您的方案)。

然后,您将诸如“本地”或“全局”或名称 (Arne) 之类的内容存储在 Admin/User 表中。然后它只是两个表之间的简单选择或连接。无需嵌套/递归。

如果您需要我为您绘制 ERD 或其他内容来解释,请告诉我。

【讨论】:

  • 不可能。 GroupsUsers 也用于系统中的其他事情。他们无法加入。
  • 好吧,我可以坐下来尝试在这里向您介绍数据库设计,直到我脸色发青为止,但这不会改变您有不允许更改的额外约束的事实数据库模型。我将编辑您的问题以反映这一点。
  • 好吧。它是来自 Active Directory 的同步,代表 AD 结构。
猜你喜欢
  • 1970-01-01
  • 2013-01-17
  • 2018-12-31
  • 1970-01-01
  • 1970-01-01
  • 2015-02-13
  • 2023-03-29
  • 2012-09-20
相关资源
最近更新 更多