4

Consider the following structure :

alt text http://aeon-dev.org/pap/pap_db.png

Ignore the table user_token.

Now, imagine that you need to get all the roles related to an user, wich may be through it's related groups or directly related to him. In case the same role appears related to a group and the user directly, the role related to the user will prevail over the role given by the group.

Is there any chance this could be done in a single query?

Cheers!

2
  • 1
    you should explain what prevail means. why does it matter where do you get the role from (group_as_role or user_has_role)? Commented Jun 8, 2010 at 15:07
  • it seems meaningless in this portion of the database, but every role will have a value attached, and if you consider a boolean case, it would make the difference Commented Jun 8, 2010 at 16:05

4 Answers 4

2

Use:

   SELECT DISTINCT r.name AS role_name
     FROM USER u
LEFT JOIN USER_HAS_ROLE uhr ON uhr.user_id = u.id 
LEFT JOIN USER_HAS_GROUP uhg ON uhg.user_id = u.id 
LEFT JOIN GROUP_HAS_ROLE ghr ON ghr.group_id = uhg.group_id 
LEFT JOIN ROLE r ON r.id = uhr.role_id
                 OR r.id = ghr.role_id
    WHERE u.username = ?
Sign up to request clarification or add additional context in comments.

Comments

2

try this:

  Select role_id 
  From user_has_role
  Where userId = @UserId
  Union
  Select role_id 
  From user_has_group g
     Join Group_has_Role gr
        On gr.GroupId = g.GroupId 
  Where userId = @UserId

1 Comment

+1: But I think you meean role_id, not Role in your select clause. FTFY
1

This query will get every role a single user has either directly or given by a group

SELECT * FROM ROLE WHERE ID IN (
    SELECT ROLE_ID
    FROM USER_HAS_ROLE 
    WHERE USER_ID = 1
    UNION
    SELECT ROLE_ID
    FROM USER_HAS_GROUP UG
    INNER JOIN GROUP_HAS_ROLE GR ON UG.GROUP_ID = GR.GROUP_ID
    WHERE USER_ID = 1
)

1 Comment

it seems to only retrieve a role if there's a similar one related directly to the user
1

You could find all distinct roles for user 1 like:

select  distinct role_id
from    (
        select  uhr.user_id
        ,       uhr.role_id
        from    user_has_role uhr
        union all
        select  uhg.user_id
        ,       ghr.role_id
        from    user_has_group uhg
        join    group_has_role ghr
        on      ghr.group_id = uhg.group_id
        where   not exists
                (
                select  *
                from    user_has_role uhr
                where   uhr.user_id = uhg.user_id
                        and uhr.role_id = ghr.role_id
                )
        ) user2role    
where   user_id = 1

Not sure how a role related to a user should "prevail", but you can assign priorities to them in the union.

2 Comments

How would you go about those priorities? I need that, in case the user has the same role assigned by a group and to himself, the role doesn't return in the query.
@yoda: You could exclude the group ones with a not exists condition, answer edited

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.