SQL Query for Multiple Many to Many Relationships - sql

I need help with a query to get All Permissions for a User.
A User can be be in 0-many Groups
Groups can have 0-many Users
A Group can have 0-many Roles
A Role can be in 0-many Groups
A Role can have 0-many Permissions
Permission can be on 0-many Roles
I have a User ID and I need to get all permissions for that User. So I need to get all the groups for a user ID, all the roles for each group for the user, and then all the permissions for the various roles.
I'm fine with the single many to many relationship query, but can seem to manage this nested query.
Example of my single many to many query:
SELECT [Permission].*
FROM [Permission] INNER JOIN
Roles_Permissions ON Permission.PermissionID = Roles_Permissions.PermissionID INNER JOIN
Role ON Roles_Permissions.RoleID = Role.RoleID
WHERE (Role.RoleID = 5)

Assuming the tables available and their structures follow the scheme suggested by permission-role_permissions-role, you can achieve what you want with a query like this:
SELECT p.*
FROM [Permission] p
JOIN Roles_Permissions rp
ON p.PermissionID = rp.PermissionID
JOIN Group_Roles gr
ON rp.RoleID = gr.RoleID
JOIN User_Groups ug
ON gr.GroupID = ug.GroupID
WHERE ug.UserID = /*desired UserID*/
Actually you don't need to join the User, Group and Role tables, because all you need from those entities is the binding between their IDs, that are already available on the relationship tables.

Related

Postgres sql to retrieve data based on aggregation and bool_or()

I have User to Role table with Many to Many relation. I need to retrieve all the roles which are not privileged(false) to any VIP users or it should be Privileged only to VIP users.
I came up with a query using aggregation and bool_or() but my result set has opt4 role. opt4 role should be ignored since its Privileged to a non- vip user (user2 - line item 6)
select
r.rolename
from
pam."role" r
join pam.user_role ur on
r.id = ur.role_id
join pam.user u on
ur.user_id = u.id
group by
r.rolename,
u.vip_flag
having
(not bool_or(ur.privileged)) or u.vip_flag=true;
Any help is much appreciated
Sounds like you simply have to add it to the HAVING clause:
HAVING ((not bool_or(ur.privileged)) OR u.vip_flag=true)
AND rolename <> 'opt4'

SQL Query: User/Group/Role and UserGroup/GroupRole Connecting User to Role

Good evening,
I have been struggling with what I think should be a fairly basic SQL query, but I can't seem to figure it out. Particularly because it seems as if there are multiple approaches (joins/ sub-queries).
I have three primary tables, and two tables connecting them.
USER
uID - PK
name, email, ...
GROUP
gID - PK
name
ROLE
rID - PK
permission
USERGROUP
uID - FK
gID - FK
GROUPROLE
gID - FK
rID - FK
These are many to many relationships, such that a user can be in multiple groups, and a group can have multiple roles.
I would like to have a query that ultimately gives me all of the roles that are connected to a given user through the groups that he belongs. Thus the uID is known, but nothing else. The output could have as few as one column with the rID, as that is all I really need for the program logic.
Is it possible to perform a query on the result of a previous query? I can easily find all the groups a user is in, and given each group, I can easily find the roles associated, but I get tripped up by the fact that there are many groups associated with a user, not just a single one which would be easier.
I would appreciate any help!
Thanks in advance.
This is just joins and aggregation:
select array_agg(distinct r.permission) as permissions
from usergroups ug join
grouproles gr
on ug.gid = gr.gid join
roles r
on gr.rid = r.id
where ug.uid = ?;
If you want the permissions in separate rows, then:
select distinct r.permission
from usergroups ug join
grouproles gr
on ug.gid = gr.gid join
roles r
on gr.rid = r.id
where ug.uid = ?;
I am leaving the distinct because different groups could share the same permissions.

Query to get user roles in DNN

I need a query to see which Roles users have in DotNetNuke.
I found this query but it gives the RoleID and not the name.
What if there are more than one role associated to a user?
SELECT Users.FirstName, Users.LastName, Users.Email,UserRoles.RoleID
FROM UserRoles
INNER JOIN Users ON UserRoles.UserID = Users.UserID
You need to include the Roles table in your query if you want the Role Names.
SELECT Users.FirstName, Users.LastName, Users.Email, UserRoles.RoleID, Roles.RoleName
FROM UserRoles
INNER JOIN Users ON UserRoles.UserID = Users.UserID
INNER JOIN Roles ON UserRoles.RoleID = Roles.RoleID
WHERE (Roles.PortalID = 0)
You also might want to include the PortalID to avoid duplicates from other portals. However I would recommend to use the DNN core functionalities do determine a user role, with the RoleController.
If there are 2 roles for a user it will bring 2 rows for the same user with different RoleID. n rows for n roles.

Database joins with three tables, one is a category / tag table

I have three database tables - one containing units, one containing categories of those units, and one containing user permissions.
If a user can access a category, they are allowed to access any units within the category.
I am trying to create a query that will retrieve a list of units they are allowed to access. So far I have a very awkward query that returns duplicates, and am a bit stuck, and it's Friday afternoon, and I wanna go home!
Here are my tables:
UnitCategory
categoryid unitid
Unit
id name
UnitCategoryUser
unitid userid categoryid
- can be null - can be null
Thanks
I suspect that UnitCategoryUser is being used as a catch-all table for the relationships between users, categories and units - so that units are recorded as belonging to categories on records where the userid is null, and users can access units even if they don't have access to their categories, where the categoryid is null.
It would also be possible for units to belong to multiple categories, and for users to be recorded as being able to access the same units mutliple times - both where a user can access multiple categories (each of which can access the same unit) and where a user has been granted access to a unit without access to the category, then subsequently granted access to the category.
The following query should return all units for a specified user:
select distinct u.name
from unit u
join unitcategory uc on u.id = uc.unitid
join unitcategoryuser ucu on uc.category_id = ucu.categoryid
where ucu.userid = YourUserID
union
select distinct u2.name
from unit u2
join unitcategoryuser ucu2 on u2.id = ucu2.unitid
where ucu2.userid = YourUserID
SELECT U.Name
FROM UnitCategoryUser UCU
JOIN UnitCategory UC ON UC.categoryid = UCU.categoryid
JOIN Unit U ON U.id = UC.UnitId
WHERE UCU.UserId = YourUserId
Does that not return your correct data? I may be missing something :x
select unit.name from unit, unitcategory, unitcategoryuser
where unit.id = unitcategory.unitid and unitcategory.categoryid = unitcategoryuser.categoryid and unitcategoryuser.userid = "Me"
Something like that?

Get the inverse of a join?

I am using SQL Server 2005. I have three tables - Users, Groups, and GroupUsers. GroupUsers contains the two PKs for a many-to-many relationship.
I have a view to get all the user information for a group as follows:
SELECT * FROM GroupUsers JOIN Users ON GroupUsers.UserID = Users.UserId
I want to create the inverse of this view - I want a list of all of the users NOT attached to a specific group. The following query would accomplish this:
SELECT * FROM Users WHERE UserID NOT IN
(SELECT UserID FROM GroupUsers WHERE GroupID=#GroupID)
However I don't want to have to specify the group, I want to know how to turn this into a view that joins the GroupID and then the UsersID and all the user info, but only for non-attached users.
I'm not sure how to do this, maybe something with the EXCEPT operator?
UPDATE:
I think this is my solution, unless someone comes up with something better:
SELECT
G.GroupId,
U.*
FROM
Groups G
CROSS JOIN
Users U
WHERE
U.UserId NOT IN
(
SELECT
UserId
FROM
GroupUsers
WHERE
GroupId=G.GroupId
)
You can use a left outer join to grab all of the users, then, blow away any user where there's a group attached. The following query will give you just the list of users where there's no group to be had:
select
u.*
from
users u
left outer join groupusers g on
u.userid = g.userid
where
g.userid is null
If you want to find all users not in a particular group:
select
u.*
from
users u
left outer join groupusers g on
u.userid = g.userid
and g.groupid = #GroupID
where
g.userid is null
This will only exclude the users in that particular group. Every other user will be returned. This is because the groupid condition was done in the join clause, which limits the rows joined, not returned, which is what the where clause does.
If I understand it correctly, you will have to do a cartersian result of users & groups and reduce the result derived from GroupUsers.
That will give you records of users which do not have any groups attached to it.
I apologize if I didn't understand the question correctly.
EDIT: Cartesian result will give you users * groups. You will have to subtract GroupUsers from it. I am sorry, I do not have SQL ready for it & can't try it out at this point.
I couldn't figure out how to get previous version to work via active record, got some of the way there but had to write an SQL in statement. I believe this also accomplishes the same thing.
SELECT * FROM Users WHERE UserID NOT IN
(SELECT U.UserID FROM GroupUsers AS G, Users as U WHERE G.UserID <> U.UserID)
Couldn't test however this query in rails worked just fine:
# Gets Pre-Clients. Has client information but no project attached
Contact.joins(:client).includes(:projects => :primary_contact).
where("contacts.id NOT IN (select contacts.id from contacts,
projects where projects.primary_contact_id = contacts.id)")
Thanks for the post got me 90% of the way there.