Inner Join of 3 Tables - sql

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

Related

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

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 |

Get results from multiple tables based on relationship table

I have dbo.Users tables
Id, Name
1, John
2, Mary
3, Michael
Then I have dbo.Phones table
Id, Phonenumber
10, 1234
11, 5555
Then I have dbo.Relationship table
Id, ChildId
1, 10
2, 11
How could I make a query that returns
Id, Name, Phonenumber
1, John, 1234
2, Mary, 5555
3, Michael, NULL
This is what I got so far.
SELECT u.Id, u.Name, p.Phonenumber
FROM dbo.Users as u
LEFT JOIN dbo.Phones as p
-- Something
SQL Fiddle
Think of the Relationship table as the middle-man between your Users and Phones tables here. It is a many-to-many relationship with a mapping table. Join your Users to the Relationship and then the Relationship to your Phones.
SELECT u.Id
,u.Name
,p.PhoneNumber
FROM dbo.Users u
LEFT JOIN dbo.Relationship r ON r.Id = u.Id
LEFT JOIN dbo.Phones p ON p.Id = r.ChildId
Think of it like:
Users: Hello Relationship, I have UserId = 1, what PhoneIds do I have for that UserId?
Relationship: Hi Users. I have PhoneId = 10 for you. I'll go talk to Phones to see what the number is.
Phones: Hi Relationships! I have PhoneNumber 1234 for you. It matches the PhoneId you gave me.
Join them on id field.I would use inner join depending on the requirement
SELECT distinct u.Id, u.Name, p.Phonenumber
FROM dbo.Users as u
LEFT JOIN dbo.Phones as p on u.id = p.id
or---
SELECT distinct u.Id, u.Name, p.Phonenumber
FROM dbo.Users as u
inner join T JOIN dbo.Phones as p on u.id = p.id
inner join dbo.relationship r on r.id = u.id
where----
try this :
Select u.Id, u.Name, p.Phonenumber
From
Users u
Left join Relationship r on r.Id = u.Id
Left join Phones p on r.ChildId = p.Phonenumber

How do I match against multiple conditions on a table join?

I have two tables:
users attributes
id|name id|name|user_id
------- ---------------
1 |foo 1 |bla | 1
2 |bar 1 |blub| 1
1 |bla | 2
How do I create a query gives users with both the "bla" AND "blub" attributes?
In this case it should only return the user "foo".
I know that the data is not normalized.
SELECT u.*, a.id, b.Id, a.name, b.name FROM users u
JOIN attributes a
ON a.User_id = u.User_id AND a.name = 'bla'
JOIN attributes b
ON u.User_Id = b.User_id AND b.name = 'blub'
Assuming an attribute association to a user is unique...
if you need 3 conditions to be true add the conditions to the in and adjust count up 1.
SELECT u.name
FROM users u
INNER JOIN attributes a on A.user_Id = u.id
WHERE a.name in ('bla','blub')
GROUP by u.name
HAVING count(*)=2
and if you don't have an unique association, or you need to join to another table you could always do...
SELECT u.name
FROM users u
INNER JOIN attributes a on A.user_Id = u.id
WHERE a.name in ('bla','blub')
GROUP by u.name
HAVING count(distinct A.name)=2
for a slight performance hit. but this allows you to join and get back additional fields which others have indicated was a detriment to this method.
This allows for scaling of the solution instead of incurring the cost of joining each time to different tables. In addition, if you needed thirty-something values to associate, you may run into restrictions on the number of allowed joins.
SELECT U.NAME
FROM USERS U
INNER JOIN
ATTRIBUTES A1
ON U.ID = A1.USER_ID
INNER JOIN
ATTRIBUTES A2
ON U.ID = A2.USER_ID
WHERE A1.NAME = 'bla'
AND A2.NAME = 'blub'
You can use the INTERSECT operator
SELECT
u.id
,u.name
FROM users AS u
INNER JOIN attributes AS a
ON u.id = a.user_id
WHERE a.name = 'bla'
INTERSECT
SELECT
u.id
,u.name
FROM users AS u
INNER JOIN attributes AS a
ON u.id = a.user_id
WHERE a.name = 'blub'
;
Here is a demo on SQL Fiddle: http://sqlfiddle.com/#!6/68986/5
More info on SET operations in SQL: http://en.wikipedia.org/wiki/Set_operations_(SQL)
SELECT u.name
FROM attributes a
JOIN users u
ON u.id = a.user_id
WHERE a.name IN ('bla','bulb')

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