Question

I have three tables

permissions

id | name
 1 | do.this
 2 | do.that
 3 | dont.this
 4 | dont.that
 5 | neither.this
 6 | both.that

roles

id | name
 1 | doer
 2 | donter

permission_role

permission_id | role_id
            1 | 1
            2 | 1
            6 | 1
            3 | 2
            4 | 2
            6 | 2

So with the below query we can get all roles a user has like so

permission_id | permission_name | role_id | role_name
            1 | do.this         |       1 | doer
            2 | do.that         |       1 | doer
            6 | both.that       |       1 | doer
            3 | dont.this       |       2 | donter
            4 | dont.that       |       2 | donter
            6 | both.that       |       2 | donter

query

SELECT 
p.id AS permission_id, p.name AS permission_name, 
r.id AS role_id, r.name AS role_name FROM permission_role pr 
JOIN permissions p ON pr.`permission_id` = p.id
JOIN roles r ON pr.`role_id` = r.id;

The question

What I am wondering is, how can we reverse this query, so create a result set listing all the permissions the roles don't have like so:

permission_id | permission_name | role_id | role_name
            3 | dont.this       |       1 | doer
            4 | dont.that       |       1 | doer
            5 | neither.this    |       1 | doer
            1 | do.this         |       2 | donter
            2 | do.that         |       2 | donter
            5 | neither.this    |       2 | donter
Was it helpful?

Solution

The logic for this type of query starts with generating all combinations of roles and permissions and then removing the ones that exist (using left outer join).

select p.id as permission_id, p.name as permission_name,
       r.id as role_id, r.name as role_name
from roles r cross join
     permissions p left outer join
     permission_role pr
     on pr.permission_id = p.id and
        pr.role_id = r.id
where pr.role_id is null;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top