The whole point of roles like the db_datareader
role is that you don't have to explicitly define read permissions for every person in that role for every object. So, you won't find a row in there for every user in the role. This is not a query, but you should essentially do this:
- Get all the users who have been explicitly granted access to that table, and for which a DENY/REVOKE does not exist.
- Get all the users who are members of any of the roles that implicitly grant read access to the given object (but again also check for explicit DENY/REVOKE).
Pseudo code (I'll update with real examples when I have time):
-- is user in role(s)? If so:
-- does role have exec on procedure - include them
-- does role have select on base table - include them
-- does role have DENY/REVOKE on procedure - exclude them
-- does role have DENY/REVOKE on table - exclude them
-- is user not in role(s)? Then:
-- does user have exec on procedure - include them
-- does user have select on base table - include them
-- does user have DENY/REVOKE on procedure - exclude them
-- does user have DENY/REVOKE on table - exclude them