Reputation: 1
I have a list of users and a list of roles. I'd like to extract reports of roles that users should have but don't and roles that they do have but shouldn't. For example
User, Dept, Role Jane, Manager, Add Jane, Manager, Modify Fred, Clerk, Modify Fred, Clerk, Inquire Dept, Task Manager, Add Manager, Modify Manager, Delete Manager, Inquire Clerk, Inquire Clerk, Add
My query should indicate that Jane is missing delete and inquire and Fred should not have modify. Currently I'm getting many duplicates as whenver I say something like manager's task <> role's task it's including records such as Add <> Modify.
Any help would be appreciated
Upvotes: 0
Views: 149
Reputation: 58619
My immediate inference from your question and data is that your tables are misdesigned, permitting ambiguity and error (missing or impoperly granted privileges) where there should be none.
However, working with what you have:
SELECT d.User, d.Dept, d."Should Have" as "Missing"
FROM ( SELECT DISTINCT udr.User, udr.Dept, dt.Task AS "Should Have"
FROM UserDeptRole udr
LEFT JOIN DeptTask dt
ON udr.Dept = dt.Dept) d
LEFT JOIN UserDeptRole udr2
ON udr2.Dept = d.Dept AND udr2.Role = d."Should Have"
WHERE udr2.Role is NULL;
Output:
+------+---------+---------+
| User | Dept | Missing |
+------+---------+---------+
| Jane | Manager | Inquire |
| Jane | Manager | Delete |
| Fred | Clerk | Add |
+------+---------+---------+
SELECT DISTINCT udr.User, udr.Role AS "Improper"
FROM UserDeptRole udr
LEFT JOIN DeptTask dt
ON udr.Dept = dt.Dept AND udr.Role = dt.Task
WHERE dt.Task IS NULL
Output:
+------+----------+
| User | Improper |
+------+----------+
| Fred | Modify |
+------+----------+
I encourage you to ask the SO community in a separate question how you can refactor your schema to avoid this very circumstance (missing or improper roles).
Upvotes: 1
Reputation: 57023
Standard SQL-99, tested on SQL Server 2008 R2:
WITH ImpliedUserRoles
AS
(
SELECT u."User", d.Dept, d.Task
FROM UserRoles u
INNER JOIN DeptTasks d
ON u.Dept = d.Dept
)
SELECT *, 'omission' AS role_error
FROM ImpliedUserRoles
EXCEPT
SELECT *, 'omission' AS role_error
FROM UserRoles
UNION
SELECT *, 'inclusion' AS role_error
FROM UserRoles
EXCEPT
SELECT *, 'inclusion' AS role_error
FROM ImpliedUserRoles;
Upvotes: 1
Reputation: 50225
The query below will not be performant on large data sets!!
You can determine all the possibilities with a cross join and then, with the right join, only care about those that are missing.
(Below is T-SQL with table variables that represent the example data)
select allTasks.[User], allTasks.[Dept], allTasks.Task as MissingTask
from @users u
right outer join (
select u.[User], d.Dept, d.Task
from @depts d
cross join (select distinct [User], Dept as [Dept] from @users) u
where d.Dept = u.Dept) allTasks on allTasks.[User] = u.[User] and allTasks.Dept = u.Dept and allTasks.Task = u.Role
where u.[User] is null
Results:
User Dept MissingTask ---------- ---------- ----------- Fred Clerk Add Jane Manager Delete Jane Manager Inquire (3 row(s) affected)
This query will then find the rows that have a task they likely shouldn't:
select u.[User], u.Dept, u.Role as ExtraRole
from @users u
left outer join @depts d on d.Task = u.Role and d.Dept = u.Dept
where d.Dept is null
Results:
User Dept ExtraRole ---------- ---------- ---------- Fred Clerk Modify (1 row(s) affected)
Upvotes: 0
Reputation: 43
Starting with your user table, left outer join to your roles table on Dept -> Dept and Role -> Task. That way, if the user is not supposed to have that right, it will return null.
sample:
select u.User, case when d.Role is null then 0 else 1 end as Allowed
from User as U
left outer join Role as d
on U.Dept = d.Dept and U.Role = d.Task
Upvotes: 0