views:

46

answers:

1

I have the following tables:

users
 - userid
 - real name
 - other stuff

roles
 - roleid
 - description
 - other stuff

functions
 - functionid
 - description

screens
 - screenid
 - description

A user can have multiple roles, as controlled by the table

user_roles
 - userid
 - roleid

Each role can have either edit, view or no access to a given function as controlled by the table

role_functions
- roleid
- functionid
- status

status is 'E' if the role has edit permission on that function, 'V' if the role has view permission on that function, and there can either be no record, or one with a 'N' status if the role has no permission on that function.

Lastly a function has multiple screens, as controlled by the table

function_screens
 - functionid
 - screenid

It's kind of a confusing mess, I know, but the requirements for the roles, functions, and screens come from different business units so I can't simplify it. However, what I need is a query that I can give to the QA department and others that given a userid, they can list all the screens, and whether they have Edit, View or No access to that screen. If that user belongs to one role that gives them 'E' permission to a function that includes a screen, and another role that gives them 'V' permission to a function that includes the same screen, then their permission to that screen is 'E'.

Right now I'm accomplishing all these lookups using a bunch of Java code with Maps of Maps, but I'm wondering if there is a simpler way to do it in a SQL script.

+4  A: 

Try this:

select s.screenid, s.description
, CASE MAX(CASE rf.status WHEN 'E' THEN 2 WHEN 'V' THEN 1 ELSE 0 END)
    WHEN 2 THEN 'E'
    WHEN 1 THEN 'V'
    ELSE 'N' END as status
from user_roles ur
join role_functions rf on rf.roleid = ur.roleid
join function_screens fs on fs.functionid = rf.functionid
join screens s on s.screenid = fs.screenid
where ur.userid = :theuser
group by s.screenid, s.description
order by s.screenid

The 2 nested cases convert E, V and N to 2, 1 and 0 and back so that MAX can be used to get the "highest" status.

Tony Andrews
I had to make one small change, but otherwise it appears to be working great. Thanks.
Paul Tomblin
@Paul Tomblin: It would've been easier if the status value was numeric, ranking in terms of access...
OMG Ponies
Sure, it would have been easier to code, but 'E' and 'V' are easier to read. I have to answer to people who want to be able to read spreadsheets.
Paul Tomblin
@Paul - I understand readability - so we make all "lookup" values like status into a table with three columns: a number, a code for spreadsheets, and a "description" for the long explanation. And sometimes, when the sort order is even more strange, we have an additional column for sort order (which is a number). It's important to take care of those who want to read spreadsheets, but don't make your job harder than it has to be just for them.
sql_mommy