i'm developing a user permission system, here is my eer
each user can have permission if:
he is a member of a group and that group have permission
he have record in user_permission table
so to get all permission that a user have, i must get a union of group permission that the user belong to, and the permission the user have in user_permission table
that the sql statement that I found as solution, but I don't know if it is the good one, (can I have the result using only one SELECT statement)
select statement:
SELECT p.name FROM permission p
JOIN group_permission as gp ON gp.permission_id = p.id
JOIN `group` as g ON g.id = gp.group_id
JOIN `user_group` as ug ON ug.group_id = g.id
where ug.user_id = 5
UNION
SELECT p.name FROM permission p
JOIN `user_permission` as up ON up.permission_id = p.id
where up.user_id = 5
here is the mysql dump of my database:
https://pastebin.com/2Kaq8fVs
The 3rd line is not necessary. You can join gp and ug via group_id. Keep your group table for securing foreign keys, but you don't need it for this kind of query. Everything else is OK for your requirement as you described it.
Note: Reading all permissions without regularly reloading them causes changed permissions not to be recognized by your application. If this is a problem, you could additionally constrain your query with a specific permission.
Related
In my database, I have users, apps, and releases. A user can have 0..n apps through a permissions table and an app can have 0..n releases.
I'm trying to get a list of users who have at least 1 app, but none of that user's apps have any releases.
The schema is roughly
users permissions apps releases
----- ----------- ---- --------
id user_id id id
email app_id app_id
I think I've got something working with this, but it appears inefficient to me because I mention the permissions table twice and I'm using nested exists clauses. Is there a more efficient way to write this query?
select u.email from users u
join permissions p on p.user_id = u.id
where not exists (
select a.id from apps a
join permissions p on p.app_id = a.id
where p.user_id = u.id and exists (
select r.id from releases r
where r.app_id = a.id
)
);
You just need to use a LEFT JOIN on releases, and then look for the case where the number of released apps (r.app_id is non-NULL) is 0. If all you want is a list of users, I don't think you need to JOIN the apps table at all, as JOINing on permissions will ensure that only users that have permission for 1 or more apps are included.
SELECT u.email
FROM users u
JOIN permissions p ON p.user_id = u.id
LEFT JOIN releases r ON r.app_id = p.app_id
GROUP BY u.email
HAVING COUNT(r.app_id) = 0
The first Join seems to be correct between users and permissions table. You just need to check whether the app_id from joined result-set exists in releases table or not. You can try this query -
select u.email from users u
join permissions p on p.user_id = u.id
where not exists ( Select 1 from releases r where r.App_id = p.app_id)
I will do something like this, hope this helps:
SELECT
u.id, u.email
FROM
users AS u
INNER JOIN
permissions AS p ON p.user_id = u.id
LEFT JOIN
releases AS r ON r.app_id = p.app_id
GROUP BY
u.id, u.email
HAVING
SUM(CASE WHEN r.id IS NOT NULL THEN 1 ELSE 0 END) = 0
Another thing you could try is a combination of left and inner joins like this:
Select
email
From users u
Inner Join (
Select
p.user_id
, p.app_id
From permissions p
Left Join releases r
on p.app_id = r.app_id
Where r.app_id is null) a
on u.user_id = a.user_id
Group by email
It's hard to tell which is faster between this and the previous posted solution without knowing the size of the different tables (and hence how many rows SQL will be trying to join).
One thing that is clear - without the 'Group by email' line at the end, you might see users' email repeated multiple times in your list. Generally, literature on SQL states that using a "group by" statement at the end of your query is a faster way to get a distinct set than a "select distinct" statement at the beginning of your query.
I have a table containing the columns user_id and lastreply_by_user_id and I'm looking for a way to match their columns with their username from the user table with id.
SELECT
table_threads.*,
table_users.username
FROM
threads AS table_threads
INNER JOIN users as table_users ON table_threads.user_id = table_users.id
OR table_threads.lastreply_by_user_id = table_users.id
WHERE
table_threads.category_id = :category_id
This is the code I have right now but this at the moment creates duplicate entries instead of one merged.
Just started with SQL recently and found the JOIN commands maybe it isn't the right one just point me in the right direction and I'll be thankful.
You need two joins to the same user table for that: one to connect by user_id, and one more to connect by lastreply_by_user_id. Use table aliases for disambiguation:
SELECT
t.*,
u.username as user_name,
r.username as last_reply_name
FROM
threads AS t
INNER JOIN users as u ON t.user_id = u.id -- actual user
INNER JOIN users as r ON t.lastreply_by_user_id = r.id -- reply user
WHERE
table_threads.category_id = :category_id
To read and output information about our network license I run a script every few minutes which calls a command line utility and dump the information in 3 mysql tables. Now I would like to get the active sessions and group name where the user belongs to (if the user is member of a group).
The 3 tables I use are:
Table: lm_session
Featureid (holds the feature id the session is connected to)
Username (the person using the license)
Workstation (system connected to the license)
In (datetime of starting the software)
Out (datetime of closing the software)
Key ( session id)
Active (yes/no)
Table lm_group
Featureid (holds the feature id the group is connected to
Name (name of the group)
License (number of licenses for the group)
Table lm_group_user
Group_id (Group Id the user is connected to)
Feature_id (Feature id *probably unnecessary)
Username (username)
At this moment I have a query like this
SELECT s.*, g.* FROM lm_session AS s
LEFT JOIN lm_group_user AS u ON s.user = u.user
LEFT JOIN lm_group AS g ON g.id = u.group_id
WHERE s.feature_id = :featureid AND s.active = 1
I do get all the users that having an active session, but the name of the group is not found properly. If a user is member of multiple groups, the s.user = u.user only finds the first group. The result is not based on a combination of s.user = u.user AND g.id = u.group_id
Can anybody help me?
i have found error in your sql query in first line:
SELECT s., g. FROM lm_session AS s ( not session )
since you are using s as alias in rest of query, but in first line you defined session as alias so that was wrong. try only s as alias in first line.
cheers.
Try to run the query below:
SELECT
s.Username,
s.Featuredid,
g.Name AS groupname
FROM lm_session s
JOIN lm_group_user gu ON s.Username = gu.Username
LEFT JOIN lm_group g ON s.Featuredid = g.Featuredid
WHERE s.Active = 1
Optional:
Add
GROUP BY a.Username
(If an user have multiple session in the lm_session table you might want to add this line to avoid duplicates, but you can start running this query without it see what happens. Since I was thinking an user might have multiple session in different software )
Sorry but I am not sure how to ask this question but I am working on a help desk application where I have tickets being created in one table. I also have another table that stores the users. My problem is with the tickets table, I have listed the user that created the ticket, the tech who will solve the ticket and a user that over sees the ticket. All three users reference the users table. So how do I can I query the tickets table and get all three users that reference the same table storing the users?
Table1: Tickets
1) Ticketnumber
2) EnteredBy User 100
3) Issue
4) FixedBy User 102
5) FixedByNotes
6) ResponsilbeUser User 103
Table2: Users
1) UserID
2) UserName
What I can do now is something like this:
Select Ticketnumber, EnteredBy, Issue, UserName FROM Tickets INNER JOIN Users
ON Tickets.EnteredBy = Users.UserID
Thanks Steve
You can extend current query to somewhat as follows:
Select Ticketnumber, Issue, Reporter.UserName, Developer.UserName, Manager.UserName FROM Tickets
INNER JOIN Users AS Reporter ON Tickets.EnteredBy = Reporter.UserID
INNER JOIN Users AS Developer ON Tickets.FixedBy = Developer.UserID
INNER JOIN Users AS Manager ON Tickets.ResponsibleUser = Manager.UserID
You need alias for joint tables if you want to get all names:
Select Ticketnumber, Issue, Informers.UserName, Fixers.UserName, Supervisors.UserName FROM Tickets
INNER JOIN Users Informers ON Tickets.EnteredBy = Users.UserID
INNER JOIN Users Fixers ON Tickets.FixedBy = Users.UserID
INNER JOIN Users Supervisors ON Ticket.ResponsibleUser = Users.UserID
WHERE...
Sorry as i am not able to understand your words, but if I assumed your need correctly.. just for a try this could help you..
if you need either of them i.e. all users who has either entered or fixed or saw an issue you can find by..
Select t.Ticketnumber, t.EnteredBy, t.Issue, u.UserID ,u.UserName FROM Tickets t
INNER JOIN Users u ON t.EnteredBy = u.UserID or t.FixedBy = u.UserID
or t.ResponsibleUser = u.UserID;
And If you need all users who has entered, fixed and saw an issue you can find by..
Select t.Ticketnumber, t.EnteredBy, t.Issue, u.UserID ,u.UserName FROM Tickets t
INNER JOIN Users u ON t.EnteredBy = u.UserID and t.FixedBy = u.UserID
and t.ResponsibleUser = u.UserID;
I am trying to make a multi-table query that I am not quite sure how to do properly. I have User, Message, Thread, and Project.
A User is associated with Message/Thread/Project as either the Creator or as it being 'shared' with them.
A Message is contained within a Thread (associated by message.thread_id and thread.id), and a Thread is contained within a Project (associated by thread.project_id and project_id).
I would like to create a query where given a User.id value, it will return all messages that the user has access to, as well as the Thread and Project name that that message is under, both as Creator or 'Shared'. I use a table to handle the 'shares'. The rough diagram is: http://min.us/mvpqbAU
There are more columns in each, but I left them out for simplicity.
I've made some assumptions on column names for message, project_name and thread_name as they are not included in the diagram.
/* Get messages where user is creator */
select u.name, m.message, p.project_name, t.thread_name
from user u
inner join message m
on u.id = m.owner_user_id
inner join thread t
on m.group_id = t.id
inner join project p
on t.project_id = p.id
where u.id = #YourUserID
union
/* Get messages where user has shared access */
select u.name, m.message, p.project_name, t.thread_name
from user u
inner join message_share ms
on u.id = ms.user_id
inner join message m
on ms.message_id = m.id
and m.owner_user_id <> #YourUserID
inner join thread t
on m.group_id = t.id
inner join project p
on t.project_id = p.id
where u.id = #YourUserID
I would urge you not to proceed with this design.
You have too many permissions levels spread over individual areas. I would suggest that you alter it so members have groups, which then in turn can be parts of projects, and threads. At a message level, you are looking at an administration nightmare having that level of permissions structure on individual messages.