使用具有模糊连接的查找表的递归视图

时间:2021-10-18 08:36:15

I don't even know how to title this question but I hope this makes sense.

我甚至不知道如何标题这个问题,但我希望这是有道理的。

I have three tables:

我有三张桌子:

  1. A table of users and their details
  2. 用户及其详细信息表
  3. A table of groups and its details
  4. 组表及其详细信息
  5. A table of groups with the lookup ID of its members which are either from the users or groups table
  6. 具有其成员的查找ID的组的表,这些成员来自用户或组表

The 3rd table has two columns:

第3个表有两列:

  1. A group ID which matches a row in the groups (2nd) table
  2. 与组(第2个)表中的行匹配的组ID
  3. A member ID which matches a row in either the users (1st) or groups (2nd) table
  4. 与用户(第1个)或组(第2个)表中的行匹配的成员标识

Notes:

笔记:

  • The IDs of users and groups table are unique against each other. For example, if a user has ID = 1 then no other user, nor any group, will have the same ID.
  • 用户和组表的ID彼此唯一。例如,如果用户ID = 1,则其他用户或任何组都不会拥有相同的ID。
  • A group can have either a user or another group as a member.
  • 组可以具有用户或其他组作为成员。

I need to dump a view of the 3rd table, fully expanding all members of each group, including the nested groups, dump the group path, and handle infinite loops. Hopefully this example makes it clear:

我需要转储第3个表的视图,完全展开每个组的所有成员,包括嵌套组,转储组路径,以及处理无限循环。希望这个例子清楚地表明:

1. users

| ID | user_name |
|----|-----------|
|  1 | one       |
|  2 | two       |
|  3 | three     |
|  4 | four      |
|  5 | five      |

2. groups

| ID | group_name |
|----|------------|
|  6 | six        |
|  7 | seven      |
|  8 | eight      |
|  9 | nine       |
| 10 | ten        |

3. group members

| group_ID | member_ID |
|----------|-----------|
|        6 |         1 |
|        6 |         2 |
|        6 |         3 |
|        7 |         4 |
|        7 |         5 |
|        8 |         1 |
|        8 |         9 |
|        8 |        10 |
|        9 |         5 |
|       10 |         1 |
|       10 |         8 |

4. output/result

| group_ID | user_ID | user_name   | group_path
|----------|---------|-------------|------------
|        6 |       1 | one         | six
|        6 |       2 | two         | six
|        6 |       3 | three       | six
|        7 |       4 | four        | seven
|        7 |       5 | five        | seven
|        8 |       1 | one         | eight
|        8 |       5 | five        | eight > nine
|        8 |       1 | one         | eight > ten
|        8 |         | [recursive] | eight > ten > eight
|        9 |       5 | five        | nine
|       10 |       1 | one         | ten
|       10 |       1 | one         | ten > eight
|       10 |       5 | five        | ten > eight > nine
|       10 |         | [recursive] | ten > eight > ten

1 个解决方案

#1


3  

Here's an answer and a live demo

这是一个答案和一个现场演示

;with cte as 
(
select id,name=user_name, type='U' from users
union
select  id, name=group_name, type='G' from groups
)
, cte2 as 
(
    select 
        user_id=c.id, 
        user_name=c.name,
        group_Id=g.group_ID,
        group_path= cast(c2.name as nvarchar(max))
    from cte c 
    left join [group members] g 
        on g.member_id=c.id and type='U'
    left join cte c2  
        on c2.type='G' and c2.id=g.group_ID
    union all
    select 
        user_id=user_id, 
        user_name=user_name,
        group_Id=g.group_ID,
        group_path= concat(c2.name,'>',c.group_path)
    from cte2 c
        join [group members] g 
        on g.member_id=c.group_Id
       join cte c2
       on g.group_ID=c2.id and c2.type='G'
        where c.group_path not like '%'+c2.name+'%'  
 )
 select 
     group_id,
     user_id,
     user_name, 
     group_path 
 from cte2
 where group_id is not null
 union all
 select 
     group_id=g.group_ID,
     user_id= NULL,
     user_name='[recursive]',
     group_path=concat(c2.name,'>',c.group_path)
 from cte2 c 
 join [group members] g
     on g.member_id=c.group_Id
     join cte c2
       on g.group_ID=c2.id and c2.type='G'
        where c.group_path like '%'+c2.name+'%'
  order by group_id,user_id

#1


3  

Here's an answer and a live demo

这是一个答案和一个现场演示

;with cte as 
(
select id,name=user_name, type='U' from users
union
select  id, name=group_name, type='G' from groups
)
, cte2 as 
(
    select 
        user_id=c.id, 
        user_name=c.name,
        group_Id=g.group_ID,
        group_path= cast(c2.name as nvarchar(max))
    from cte c 
    left join [group members] g 
        on g.member_id=c.id and type='U'
    left join cte c2  
        on c2.type='G' and c2.id=g.group_ID
    union all
    select 
        user_id=user_id, 
        user_name=user_name,
        group_Id=g.group_ID,
        group_path= concat(c2.name,'>',c.group_path)
    from cte2 c
        join [group members] g 
        on g.member_id=c.group_Id
       join cte c2
       on g.group_ID=c2.id and c2.type='G'
        where c.group_path not like '%'+c2.name+'%'  
 )
 select 
     group_id,
     user_id,
     user_name, 
     group_path 
 from cte2
 where group_id is not null
 union all
 select 
     group_id=g.group_ID,
     user_id= NULL,
     user_name='[recursive]',
     group_path=concat(c2.name,'>',c.group_path)
 from cte2 c 
 join [group members] g
     on g.member_id=c.group_Id
     join cte c2
       on g.group_ID=c2.id and c2.type='G'
        where c.group_path like '%'+c2.name+'%'
  order by group_id,user_id