MySQL 8.x here. I have the following tables:
[users] (users in the system)
===
user_id
user_username
user_password_enc
user_first_name
user_last_name
[events] (CRUDdable things the users can participate in)
===
event_id
event_name
event_date
event_location
[event_roles] (coarse-grained, event-specific roles that users can be assigned to)
===
event_role_id
event_role_name
event_role_label -- ex: EVENT_ADMIN, EVENT_REP, EVENT_FOLLOWER
[event_permissions] (granular permissions that get assigned to roles)
===
event_permission_id
event_permission_name
event_permission_label -- ex: CAN_VIEW_LOCATION, CAN_CHANGE_DATE, CAN_CHANGE_LOCATION, CAN_CANCEL_EVENT
[event_permissions_x_roles] (crosswalk table mapping permissions to roles)
===
event_permissions_x_role_id
event_permission_id
event_role_id
[event_user_roles] (which users are assigned to which event roles)
===
event_user_role_id
event_id
user_id
event_role_id
I now want to write a query that asks the following question:
Does user_id = 234 have CAN_CHANGE_LOCATION permission to event_id=123?
My best attempt thus far:
SELECT
event_permission_label
FROM
event_permissions_x_roles
INNER JOIN
event_permissions
ON
event_permissions_x_roles.event_permission_id = event_permissions.event_permission_id
WHERE
event_role_id = (
SELECT
event_role_id
FROM
event_user_roles
WHERE
user_id = 234
AND
event_id = 123
);
However this will only give me a list of event_permission_labels that the user_id=234 has for event_id=123.
That's close to what I want, but I want my query to go further and check that list to see if CAN_CHANGE_LOCATION is part of that list. I don't know if there's a way to write this so that it returns a boolean true/false (yes user does have the desired permission for the given event; or no the user does not, etc.). Can anyone spot where I'm falling a bit short?
Schematically:
SELECT EXISTS ( SELECT NULL
FROM {joined tables set}
WHERE t1.user_id = 234
AND t2.event_permission_label = 'CAN_CHANGE_LOCATION'
AND t3.event_id = 123 )
Related
I have the following three tables:
templates <-----> templatesubscription <-----> user
table template:
id | name
table user
id | name | ...
table templatesubscriptions
id | template_id | user_id
Each user can have n template subscriptions.
Each template subscription can have 1 user.
Each template has n template subscriptions.
Each template subscription has 1 template.
Now I want to check if the currently logged in user (User ID = 10) can edit the template with the ID = 0. Only if the user has an template subscription for this template he can edit it.
Now I could make 2 queries. First I will get the template subscription of the current user with the template id:
SELECT * FROM templatesubscription WHERE user_id = 10 AND template_id = 0
Now I can check if the return value is null, if yes the user will get an error message. If the result isn't empty, I will get the template of the template table:
SELECT * FROM templates WHERE id = 0
But this approach doesn't seems really nice to me. Can I combine both statements in one querie? The return value should be the template or null if the user has no template subscription for this template.
You can have them both together using a where condition. Simply there is output if the user has permission.
SELECT *
FROM templates
WHERE id = 0 and 1=(SELECT 1 FROM templatesubscription WHERE user_id = 10 AND template_id = 0)
Learn about joins, here's a good overview.
So in your case, you want to inner join between subscriptions and templates, to only get the subscriptions the user has access to:
SELECT t.* -- it's better to list all the columns than use *
FROM templates t
INNER
JOIN templatesubscription ts
ON t.id = ts.template_id
WHERE ts.user_id = 10
AND ts.template_id = 0
So this will return the row(s) from templates table only if there is a record in templatesubscription for that user_id.
The query is trying to return all the roles from lprovider table for a given provider if his role is not ExternalHealthCoach. If his role is ExternalHealthCoach then return ExternalHealthCoach as provider's role.
select
role
from lprovider
where provider_id = 63 and
role in (select case when role = 'ExternalHealthCoach' then role
else (select distinct role from lprovider) end from lprovider);
Sample records in Lprovider table:
role_column
ExternalHealthCoach
InternalHealthCoach
Doctor
FrontDesk
Admin
Co-ordinator
If the provider_id = X and if he is not ExternalHealthCoach then I want to return all the roles not a just only doctor.
Ex:
If provider_id = 63 and his role = doctor then the query should return all the roles in the lprovider table. i.e.
ExternalHealthCoach, InternalHealthCoach, Doctor, FrontDesk, Admin, Co-ordinator
But getting an error while executing.
Error Code: 1242 subquery returns more than 1 rows
Thanks in advance.
A case *expression` returns one value, not a list of values.
I think the logic you want is:
select l.role
from lprovider l
where l.provider_id = 63 and
(l.role = 'Rejuvalyte-ExternalHealthCoach' or
l.role in (select l2.role from lprovider l2)
);
Note that select distinct is not needed when using in with a subquery.
This logic is still a bit confusing. I don't think the in part of the condition does anything. You can just remove it.
I am trying to check if the current user is already following the selected user, and I am doing this like so:
(I know it's not the best way, but as I am new to MYSQL this is as much as I have been able to come up with)
SELECT EXISTS (SELECT 1 FROM Activity WHERE IdOtherUser = 86 AND id = 145)
I am '145' and the user I selected is '86'.
Now that return '0' If I am not following and '1' If I am following that person.
Seems to be working already but it definetly needs improving!
Now what I would like to do is count the followers in the same query.
So count the people I am following and the people following me.
'Activity' is the table where I store the followers and I save them like this:
'id' = me
'idOtherUser' = other user I followed
'type' = type of action "follow"
I have done count's before when calculating the like counts, but I just cannot get my head around this!!
If anyone could spare some time to help me it is much appreciated!
I am sorry if the question is not the best, but I am still learning and trying my best to format them as clear as possible to understand.
Thanks in advance!!
If you trying to count the followers from specific id from table Activity you might do this way:
SELECT COUNT(idOtherUser) AS "I Follow",
(SELECT COUNT(idOtherUser) FROM Activity WHERE idOtherUser = 145 AND type = "follow"
) AS "FOLLOW ME",
(SELECT COALESCE(id,0) FROM Activity WHERE IdOtherUser = 86 AND id = 145 AND type = "follow")
FROM Activity WHERE id = 145 AND type = "follow"
you can use a "correlated subquery" to simplify the query and you might want distinct in the count also (depends on you data). I would avoid using spaces in column aliases too.
SELECT
COUNT(DISTINCT A1.idOtherUser) as i_follow
, (
SELECT
COUNT(DISTINCT A2.id)
FROM Activity A2
WHERE A2.idOtherUser = A1.id
AND A2.type = 'follow'
) as following_me
FROM Activity A1
WHERE A1.id = 145
AND A1.idOtherUser = 86
AND A1.type = 'follow'
Try it with distinct then without, if the result is the same leave distinct out of the query.
Say I have the following tables
User
__________
id
username
email
FriendGame
__________
id
useroneid
usertwoid
status
I want to get games that the current user is part of, so I do this:
SELECT *
FROM FriendGame
WHERE useroneid=1663702020516206
OR usertwoid=1663702020516206
AND STATUS =1;
This is fine. Now I want to join the username, but only for the user that ISNT the supplied user (1663702020516206) since in FriendGame the given user exists EITHER as useroneid or usertwoid.
You can pretty much translate your logic directly into an on clause:
SELECT fg.*
FROM FriendGame fg JOIN
User u
ON (fg.useroneid = 1663702020516206 and fg.usertwoid = u.id) or
(fg.usertwoid = 1663702020516206 and fg.useroneid = u.id)
WHERE 1663702020516206 in (fg.useroneid, fg.usertwoid) AND
STATUS = 1;
Actually, the where clause is not necessary to get the right result set, but I think it makes the intention of the query clearer.
I'm trying to perform what I assume is a very simple query on a MySQL DB. Here's my table setup;
Table 1 - CMS_AccessLevels
accessLevel
titleColor
Table 2 - CMS_Users
userID
username
userEmail
userAvatar
userSignature
accessLevel
I've already got this query;
SELECT `titleColor` FROM `CMS_AccessLevels` WHERE `accessLevel` = (SELECT `accessLevel` FROM `CMS_Users` WHERE `userID` = 3)
This works correctly and returns the correct titleColor value based on the accessLevel matching across both tables.
Now, what I want to do is also grab some of the values from CMS_Users as well. For the sake of simplicity, let's assume I want to grab only a few of the values, so my result set might look something like this;
userID|username|userAvatar|accessLevel|titleColor
-------------------------------------------------
0 |Scott |image.png | 6 |#FFFFFF
or as a PHP Array (shown just so you can see the logical layout if the above table didn't make sense);
array('userID' => $result['userID'],
'username' => $result['username'],
'userAvatar' => $result['userAvatar'],
'accessLevel' => $result['accessLevel'],
'titleColor' => $result['titleColor'];
Let's say I want to get userID, userName, userAvatar and accessLevel from CMS_Users, and titleColor from CMS_AccessLevels where CMS_Users.userID is equal to '3', remembering that CMS_AccessLevels.accessLevel and CMS_Users.accessLevel MUST match.
Realistically, the only piece of data I know before running the query is userID.
Is it possible to do this with a single query?
Try this:
SELECT u.userID, u.username, u.userAvatar, u.accessLevel, al.titleColor
FROM CMS_AccessLevels al
INNER JOIN CMS_Users u
ON u.accessLevel = al.accessLevel
WHERE u.userID = 3
You are using subqueries whereas joins will be the right choice. You might try something like
SELECT a.titleColor AS titleColor, u.username AS username FROM CMS_users u INNER JOIN CMS_AccessLevels a ON u.accessLevel = a.accessLevel WHERE u.userID = '3'