Selecting users who are in the same group with "name" - sql

Users
id username
1 ryan
2 mike
3 annie
4 lisa
Groups
id name
1 football
2 hockey
Permissions
user_id group_id
1 1
1 2
2 1
4 2
So I'm looking for every username, who belong to at least one same group with username ryan. I'd also like to know everyone who is not in the same group.
SELECT Users.username
FROM Users
LEFT JOIN Permissions ON Users.id = Permissions.user_id
LEFT JOIN Groups.id = Permissions.group_id
WHERE Users.id;
So this is how I got it started, but have no idea how to continue.

Here is one method:
with ug as (
SELECT u.username, g.name
FROM Users u JOIN
Permissions p
ON u.id = p.user_id
)
SELECT DISTINCT ug.username
FROM ug
WHERE EXISTS (SELECT 1
FROM ug ug2
WHERE ug2.group_id = ug.group_id AND
ug2.username = 'Ryan'
);
The above assigns the group name to each user and then treats this as a single table. EXISTS is used to determine if the groups overlap.
Note that groups is not needed because you are not asking for the name of the group. The id is sufficient to answer the question.
I am not a big fan of using select distinct. It usually means that the database engine is doing more work than necessary -- creating duplicates and then removing them.
Here is an alternative solution that uses exists:
select u.*
from users u
where exists (select 1
from permissions p join
permissions pr
on pr.group_id = p.group_id join
users ur
on pr.user_id = ur.user_id and
ur.username = 'Ryan'
where p.user_id = u.id
);

You can do it with multiple joins of Users and Permissions:
select uu.username
from Users u
inner join Permissions p on p.user_id = u.id
inner join Permissions pp on pp.group_id = p.group_id
inner join Users uu on pp.user_id = uu.id and pp.user_id <> u.id
where u.username = 'ryan'
See the demo.
Results:
| username |
| -------- |
| mike |
| lisa |

Related

SQL select max value with join

I have two table:
USER (that can have multiple profiles)
id | name | profile | ...
BET
id | profile_id | date | amount | ...
I need to select name, and the date of the bet with maximum amount betted for every user from every profile.
So the output should be something like this:
name | max_amount | date_max_amount
USER (that can have multiple profiles)
It means that the user can have multiple ids and you would be identifying users on the basis of their names and have their max bids
SELECT u.name, MAX(b.amount)
FROM USER u
LEFT JOIN BET b ON (u.id = b.profile_id)
GROUP BY u.name
Then you can
SELECT u.name, d.max_amount, b.date AS date_max_amount
FROM USER u
LEFT JOIN (
SELECT u.name, MAX(b.amount) as max_amount
FROM USER u
LEFT JOIN BET b ON (u.id = b.profile_id)
GROUP BY u.name
)d ON (u.name = d.name)
LEFT JOIN BET b ON (u.id = b.profile_id AND b.amount = d.max_amount)

How to combine two SQL queries in one

I have tables user, participant and chat. I need to get all users in a specific chat and amount of chats that user in by chat name. For example current tables:
user chat participant
id|name id|name user_id|chat_id
1|Mike 1|School 1|1
2|John 2|Football 2|1
3|Sara 3|Gym 1|2
3|3
And by keyword "School" I want to get this
Mike|2
John|1
I have two queries to get first and second column in result but don't know how to combine it:
SELECT user.name FROM user
JOIN participant ON (user.id = participant.user_id)
JOIN chat ON (participant.chat_id = chat.id) WHERE chat.name = 'School';
That gives me
Mike
John
And
SELECT user.name, COUNT(*) FROM user
JOIN participant ON (user.id = participant.user_id) GROUP BY user.name;
returns
John|1
Mike|2
Sara|1
So how to combine it?
TRY THIS
SELECT p1.name, COUNT(p.user_id) totUser
FROM participant p
INNER JOIN (select u.id, u.name FROM participant p
inner JOIN chat c ON c.id = p.[chat_id]
INNER JOIN user u ON u.id = p.user_id
AND c.name = 'School') p1 ON p1.id = p.user_id
GROUP BY p1.name
using Subquery and joins :
select u.name,count(p.chat_id) as 'Count' from user u
inner join participant p on p.user_id = u.id
where
p.user_id in ( select user_id from participant pp inner join chat cc on cc.id = pp.chat_id where
cc.name = 'School' )
group by u.name
order by Count desc
Output :

Inner Join of 3 Tables

In Table Approver:
No Userid
1 3
2 7
In Table Users:
No UserID RoleID
1 3 1
2 4 1
3 5 2
4 7 3
Table Roles
RoleID Name
1 ABC
2 BCD
3 CDE
I want to select rolename of users in table approver like:
Userid Name
3 ABC
7 CDE
I'm not 100% sure why approver.no is on the user and approver table.... I'm going to assume userId is unique in both situation..... if thats the case this should work:
select
u.userid,
r.name
from
Approver as a
inner join [Users] as u on a.userId = u.UserId
inner join [Roles] as r on u.roleId = r.roleId
if that is NOT the case and you need the approver.no user.UserId combo to be unique than the following should work:
select
u.userid,
r.name
from
Approver as a
inner join [Users] as u on a.userId = u.UserId
and a.No = u.No
inner join [Roles] as r on u.roleId = r.roleId
the differences between these two as far as the result set concerns can be found here: http://sqlfiddle.com/#!3/0daa9/4
Notice that the second query returns a single result against the provided data
select
a.Userid,
r.Name
from
Approver a
join Users u on a.no = u.no
join Roles r on u.RoleID = r.RoleID
SELECT U.UserID,
Name
FROM Approver A
JOIN Users U
ON A.UserId = U.UserId
JOIN Roles R
ON R.RoleId = U.RoleId
SQL FIDDLE DEMO
SELECT Approver.UserId, Name from Approver INNER JOIN Users
on Approver.No=Users.No
INNER JOIN Roles
on Users.RoleID=Roles.RoleID

Find users not in an organization

Given this data:
users
id name
== ====
1 Alice
2 Bob
3 Carl
organizations
id name
== ====
1 Aaa
2 Bbb
memberships
id organization_id user_id
== =============== =======
1 1 1
2 2 1
3 1 2
I want to find users that do not belong to a particular organization X:
users with no membership records at all
AND
users with membership records, but not for organization X.
For example, I want users that are not in organization 2. I am expecting:
users.id
========
2
3
Attempting with this join isn't working:
SELECT *
FROM users left join memberships on memberships.user_id = users.id
where memberships.id is null or memberships.organization_id <> 1
It's returning users 1,2,3 since 1 matches on the second where condition.
Is there an efficient way to do this?
Restricting your JOIN to organization of 2 and then testing for null is the one way to do what you're looking for e.g.
SELECT *
FROM users
LEFT JOIN memberships
ON memberships.user_id = users.id
AND memberships.organization_id = 2
WHERE memberships.id IS NULL
You can also use NOT IN
SELECT *
FROM users
WHERE id NOT IN (SELECT user_id from memberships where organization_id = 2 )
You can also use the minus set operator:
select "name" from users
minus
select "name" from users u inner join memberships m on u.id = m.user_id inner join organizations o on m.organization_id = o.id and o."name" = 'X'
select Users.*
from users
inner join memberships
on Users.id = memberships.id
left join organizations
on memberships.organization_id = organizations.id
where memberships.id is null AND memberships.organization_id = 2
Here's another option using the exists clause:
select * from users
where not exists
(select memberships.id from memberships
inner join organizations on memberships.organization_id = organizations.id
and memberships.user_id = users.id
where organizations.id = 2)
select u.*
from users u
left join memberships m
on u.id = m.user_id
left join organizations o
on m.organization_id = o.id
where m.organization_id not in (2)
EDIT: modified to include all users

Simple SQL Select Query between 2 tables

I have 2 table
First table - userTable
usedID userName
1 someName
2 someOthername
Second Table - ratingTable
userID ratingValue
1 5
1 3
1 5
1 3
2 5
2 5
2 3
2 5
I need to write a SQL query that will get all userID in ascending order for number of times rated (5 star)
SELECT u.userID, u.userName, COUNT(*) AS ratingCount
FROM userTable u
INNER JOIN ratingTable r
ON u.userID = r.userID
AND r.ratingValue = 5
GROUP BY u.userID, u.userName
ORDER BY ratingCount
Here's one example:
select u.UserId
, count(r.ratingValue)
from userTable u
left join
ratingTable r
on u.userID = r.userID
and r.ratingValue = 5
group by
u.UserID
order by
count(r.ratingValue)
If the result does not require users without any five star ratings, you can even omit the userTable altogether.
I assume you mentioned 5 stars as the rating system you are using and not that you only wish to retrieve users with ratings of 5 stars.
SELECT u.userName, avg( r.ratingValue ) as averageRating
FROM userTable u
LEFT JOIN ratingTable r ON u.userID = r.userID
GROUP BY u.UserID
ORDER BY avg( r.ratingValue ) desc
This will get the average rating of each user and display their names.
userName averageRating
test1 4.5000
test2 1.7500