简体   繁体   中英

SQL Server : query multivalued table recursive

I have a SQL problem which I cannot solve

There are 2 tables mms and mms_mv which are linked via object_id .

The mms_mv is a multivalue table and the content is group memberships and group manager which also can be an other group.

This runs on SQL Server

mms :

|object_id|attribute_type|objectSid|
| 1       |user          | a       |
| 2       | group        | b       |
| 3       | group        | c       |
| 4       | group        | d       |
| 5       | group        | f

mms_mv :

|object_id|attribute_name|reference_id|
| 2       | member       | 1          |
| 3       | manager      | 1          |
| 4       | manager      | 2          |

I am trying to find out which groups a user can manage either directly or indirectly via nested groups.

In the example above the user (1) is member of group Number 2 and group 2 is Manager of group 4 user 1 is manager of group 3 directly.

Which groups can be managed by the user?

So the output I need is group 3 and 4

select 
    accountname, objectsid, mms1.reference_id as ManagerID, 
    mms2.object_id
from 
    dbo.mms_mv_link as mms1 with (nolock) 
inner join 
    dbo.mms_metaverse as mms2 with (nolock) on mms1.object_id = mms2.object_id
where 
    mms2.object_type ='group' 
    and mms1.attribute_name = 'manager' 
    and mms1.reference_id in (1, 3)

This is the best I came up with to find out which of all Group id's and user id I submitted are Manager of a Group. I used an other lookup to get the groups a user is in.

My problem are the nested groups, by long thinking and googling I am not sure if it is even possible to create such a query.

I can find out all groups a user is member of, but I also need the Groups in which these groups are members.

Well I am happy if anyone has some ideas or hints for me to figure this one out.

I am even happy if you have a recommendation for a good sql book which covers such complex queries.

Thank you all for helping me.

I think that the following recursive CTE will give you what you want:

;WITH cte AS
(
   SELECT m2.object_id AS groupID, m2.attribute_name
   FROM @mms AS m1
   INNER JOIN @mms_mv AS m2 ON m1.object_id = m2.reference_id
   INNER JOIN @mms m3 ON m2.object_id = m3.object_id
   WHERE m1.attribute_type = 'user' AND m3.attribute_type = 'group'

   UNION ALL

   SELECT m.object_id AS groupID, m.attribute_name
   FROM cte AS c
   INNER JOIN @mms_mv AS m ON c.groupID = m.reference_id
)
SELECT *
FROM cte
WHERE attribute_name <> 'member'

The so-called 'anchor' query of the CTE returns all groups that every user either manages or is member of. Using recursion we get all other groups managed by either the groups of the original set or by any 'intermediate' set.

With these data as input:

DECLARE @mms TABLE (object_id INT, attribute_type VARCHAR(10), objectSid VARCHAR(10))
DECLARE @mms_mv TABLE (object_id INT, attribute_name VARCHAR(10), reference_id INT)

INSERT @mms VALUES
( 1, 'user',  'a'),
( 2, 'group', 'b'),      
( 3, 'group', 'c'),       
( 4, 'group', 'd'),       
( 5, 'group', 'f')

INSERT @mms_mv VALUES
( 2, 'member', 1),
( 3, 'manager', 1),
( 4, 'manager', 2),
( 5, 'manager', 3)

the above query yields the following output:

groupID attribute_name
----------------------
3       manager
5       manager
4       manager

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM