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

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.

Related

group_concat multiple rows where given condition

I have 3 tables (User, User_usergroups , usergroup). I would like to get a list of user who has usergroup equal to "member" and other groups (group_concat) belonging to this user. How do I do that?
I got the first part of the query, but I could not get other groups, aggregated groups of this user (I like to use group_concat to concatenate other groups in one field.
SELECT user.userId, (group_concat(group_.name)???)
FROM User_ user join Users_UserGroups userGroups
on user.userId= userGroups.userId
join UserGroup group_ on userGroups.userGroupId = group_.userGroupId
WHERE group_.name="member";
Assume that is the 3 tables
The outcome will be
Many thanks for your great help.
It looks like my query is so complex and it has down vote from the administrator or someone. I wish whoever did this could add their comment to my query so that, in the future, I will know what I need to do to clarify my question to the community or make my question better. Here is the answer to my question.
First retrieve the list of userId.
Then join this "member" table with other tables to find the result from the list of retrieved ID (step 1).
As we aggregate the name of the groups, we need to use groupby.
Keywords to resolve this problem is to use an alias for subquery or nested SQL
select member.userid, member.screenName, group_concat(member.name)
from (SELECT User_.userid userid, User_.screenName screenName , UserGroup.name name
FROM UserGroup
JOIN Users_UserGroups
ON UserGroup.userGroupId = Users_UserGroups.usergroupid
JOIN User_
on Users_UserGroups.userId = User_.userId
WHERE UserGroup.name = "member")member
JOIN Users_UserGroups
ON member.userid = Users_UserGroups.userId
JOIN UserGroup
on UserGroup.userGroupId=Users_UserGroups.userGroupId
GROUP BY member.userid;

How to select records from database table which has to user id (created_by_user, given_to_user) and replace users id by usernames?

This is task table:
This is user table:
I want to select user tasks.
I would give from backend ("given_to_user) id.
But The thing is I want that SELECTED data would have usernames instead of Id which is (created_by_user and given_to_user).
SELECTED table would look like this.
Example:
How to achieve what I want?
Or maybe I designed poorly my tables that It is difficult to select data I need? :)
task table has to id values that are foreign keys to user table.
I tried many thinks but couldn't get desired result.
You did not design poorly the tables.
In fact this is common practice to store the ids that reference columns in other tables. You just need to learn to implement joins:
SELECT
task.id, task.title, task.information, user.usename AS created_by, user2.usename AS given_to
FROM
(task INNER JOIN user ON task.created_by_user = user.id)
INNER JOIN user AS user2 ON task.created_by_user = user2.id;
Do you just want two joins?
select t.*, uc.username as created_by_username,
ug.username as given_to_username
from task t left join
users uc
on t.created_by_user = uc.id left join
users ug
on t.given_to_user = ug.id;
This uses left join in case one of the user ids is missing.

SQL Query for Multiple Many to Many Relationships

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.

How do I establish a SQL query for this many-to-many table?

I'm building this bartering-type function in this site using PHP/MySQL and I'm trying to create a query that responds with the following fields:
owner's username, title, offerer's username, offerer's item
Basically I have three tables here with the following fields:
users
user_id, username, email
items_available
item_number, owner_id (foreign key that links to user_id), title
offers_open
trade_id, offerers_id (fk of user_id), offerers_item(fk with item_number), receivers_id (fk from user_id)
How do I do this? I've seen some references to many-to-many SQL queries but they don't seem to particularly fit what I'm looking for (for example, the offerers_id and the owner_ids refer to different users_id in the Users table, but how do I make them distinguishable in the sql query?)
If I understand correctly, this is what you are looking for:
SELECT owner.username, oferrers.username, ia.title
FROM offers_open o
INNER JOIN users AS offerers
ON o.offerers_id = offerers.user_id
INNER JOIN items_available AS ia
ON o.offerers_item= ia.item_number
INNER JOIN users AS owner
ON ia.owner_id = owner.user_id
I don't see a title on the users table, so didn't include one.
I'm not sure exactly what output you want, but since your users table will appear twice in the query, they need to be aliased like so:
SELECT offerer.username AS offerer_username, title, receiver.username AS receiver_username
FROM users AS owner
JOIN items_available ON owner_id = owner.user_id
JOIN offers_open ON offerers_item = item_number
JOIN users AS receiver ON receivers_id
Again, don't know if that's what you want, but hope you get the idea.
It sounds as you need an alias of the users table.
Something like?
select
u.*, ia.*, oo.*,u2.*
from
users as u,
items_available as ia,
offers_open as oo,
users as u2
where
u.user_id = ia_user_id and
oo.user_id = u2.user_id and
oo.item_id = ia.item_id

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.