how to write conditional left join - mysql

I have 2 tables named user and userFriend. I want all user from user table, and specific member from userFriend table. Then I want to join both of them...
user
userID userName
1 aaa
2 bbb
3 ccc
4 ddd
5 eee
userFriend
userFriendID userID friendUserID
1 1 2
2 2 3
3 1 4
4 4 2
So if my userID = 1,
then I want result like
userID userName userFriendID friendUserID
2 bbb 1 2
3 ccc NULL NULL
4 ddd 3 4
5 eee NULL NULL
so in this way I want conditional for 2nd table, I only want to join 2nd table having userID = 1 with 1st table using left join.

It's an unconventional thing to ask for... but this gives you the results you want.
SELECT u.userID, u.userName, uf.userFriendID, uf.friendUserID
FROM user u
LEFT JOIN userFriend uf ON u.userID = uf.friendUserID AND uf.userID =1
WHERE u.userID !=1

For what you want you dont need a query from both tables. Just using userFriend will give you the data. You'll need the user table for names only.
SELECT DISTINCT userID FROM userFriend
WHERE friendUserID = ?
this will give you all users that have that specific friend that you need.
Optionally you can add a INNER JOIN to see what are the names:
SELECT DISTINCT f.userID, u.name
FROM userFriend f
INNER JOIN users u ON u.userID = f.userID
WHERE friendUserID = ?
UPDATE
A comment about your structure. You don't need the userFriendID. The combination of userID and friend ID can be your key.
UPDATE of the query
SELECT * FROM users u
LEFT JOIN userFriend f on u.userID = f.userID
WHERE f.friendUserID = ?
This will return you all users that have the friend X. The left join is not important in this query. This specific condition is making it irrelevant.
To get exactly what you want you need to execute this.
SELECT * FROM users u
LEFT JOIN (
SELECT DISTINCT * FROM userFriend f
WHERE friendID = 4
) x ON u.id = x.userId
It can be done using a subquery, but I dont think is the most logical way of organizing your tables.

Related

How to fix Sql query

Please i have been trying to get a query to return the friends a user has,in my members table, i have user id ,firstname and lastname of the member, i have user id column and friend id column in the friends table, now i am combining my members table with friends table so i can get the name of a friends.
users table
user_id firstname lastname
2 John drake
3 Hamer Joy
4 Finter Richy
friends table
friends_id user_id friend_id
1 2 3
2 4 2
3 4 3
here is the query i executed
SELECT a.friends_id,a.user_id,
a.friend_id, b.firstname, b.lastname
FROM friends AS a,users As b
WHERE (a.friend_id = b.user_id OR a.user_id = b.user_id) AND
(a.friend_id = 2 OR a.user_id =2)
here is the result i am getting
friends_id user_id friend_id firstname lastname
1 2 3 John drake
1 2 3 Hamer Joy
3 4 2 John drake
3 4 2 Finter Richy
This is the result i am expecting
friends_id user_id friend_id firstname lastname
1 2 3 Hamer Joy
3 4 2 Finter Richy
perhaps take a union of the specified individual's friends plus the users who have him as a friend:
select a.friends_id, a.user_id, a.friend_id, b.firstname, b.lastname
from friends a, users b
where a.user_id = 2 and b.user_id = a.friend_id
union
select a.friends_id, a.user_id, a.friend_id, b.firstname, b.lastname
from friends a, users b
where a.friend_id = 2 and b.user_id = a.user_id
This is all a single query resulting from the union of 2 inner queries.
I think the problem with your original query is that you are using an OR condition in your joins. Normally OR's in join conditions are not helpful.
Here is another solution that is a bit shorter and uses ANSI join syntax so you can clearly see the projections. Disclaimer, I haven't tested it in a database, so there may be an error. However, you can also access the original user name as well if you like (I've added that as the last two columns).
select F.friends_id, U.user_id, FR.user_id,
FR.firstname, FR.lastname,
U.firstname, U.lastname
FROM users U join Friends F on
U.user_id = F.user_id
JOIN Users FR on
F.friend_id = FR.user_id
where U.user_id = 2 or FR.user_id = 2
;
As a general rule, using the ANSI join syntax makes your query much easier to read and helps to ensure all of the join conditions are specified. It also gives you easy access to more join types.

How to set up QUERY with different actions based on result value?

I need help on how to set up an QUERY that will result in different outputs based on the results that it achieves on the way and I'm completely stuck!
I'll give you some more details, first of all, here's my current database setup:
#USERS
id username etc..
1 alex123
2 bonnie9
3 clyde_x
#COURSES
id course_name visibility etc..
1 Name 1 1
2 Name 2 0
3 Name 3 1
#COURSE_ENROLMENT
id user_id course_id
1 1 1
2 1 2
3 3 1
The scenario is as following..
I need to list the courses to the users that are enrolled to it, which is quite easily done by something like:
SELECT
*
FROM COURSES C
JOIN COURSE_ENROLMENT E ON C.ID = E.COURSE_ID
However. If the course visibility (Database: Course, Column: visibility) is set to be visible for everyone = 1, then it will override or just ignore the enrolment and show the course to all users anyway.
How can I achieve something like this? I've tried to research CASE but can't really figure out how to proceed. Greatest thanks for any help!
To answer this you're going to need to LEFT JOIN your COURSE and COURSE_ENROLLMENT tables using an OR, so either the person is enrolled in the subject OR the visibility is set to 0.
If you change your JOIN to a LEFT JOIN, that will give you all courses, regardless of whether someone has enrolled in them or not. You can then filter out the courses which have not had anyone enrolled and are not visible by checking for visibility = 1:
SELECT *
FROM Courses C
LEFT JOIN Course_Enrolment E ON C.id = E.course_id
WHERE C.visibility = 1 OR E.id IS NOT NULL
Output:
id course_name visibility id user_id course_id
1 Name 1 1 1 1 1
2 Name 2 0 2 1 2
1 Name 1 1 3 3 1
3 Name 3 1 null null null
Demo on dbfiddle
If visibility=1 means that the course will be returned for all users, then you can do it with a cross join for that case and UNION ALL:
select c.course_name, u.username
from users u
inner join course_enrolment e on e.user_id = u.id
inner join (
select * from courses where visibility = 0
) c on c.id = e.course_id
union all
select c.course_name, u.username
from users u
cross join (
select * from courses where visibility = 1
) c
order by course_name, username

Exclude Staff Members

I have a user table:
id, userID, name, postcode
2 99 Bob AAA BBB
3 8384 Jim CCC DDD
And I have a user-keys table:
id, userID, keyID, val
1 435 3 1
2 773 8 0
3 99 2 1
4 99 5 1
5 99 2 1
Where keyID = 2 indicates that it is a staff member. I want to get all the userIDs from user table that are not staff members. So far I have the following SQL:
SELECT u.`userID` FROM `users` u
WHERE u.`userID` IS NOT NULL AND u.`userID` != 0;
However this does not exclude all users that have an entry in user-keys table with a keyID value of 2 and val of 1.
How can I perform this?
Edit: I neglected to state that any user may have multiple entries in the user-keys table, and I just want one list of userID from the user table, So really the results I am looking for from the above tables would simply be 8384.
You can try the following join query:
SELECT
t1.userID
FROM user t1
LEFT JOIN
(
SELECT DISTINCT userID, keyID -- you don't need DISTINCT here, but it may help
FROM `user-keys` -- and it makes the logic a bit clearer
WHERE keyID = 2
) t2
ON t1.userID = t2.userID
WHERE t2.userID IS NULL
The logic used here is that we retain all users from the user table who do not appear in user-keys with a keyID of 2, or who do not appear in user-keys at all.
Follow the link below for a demo in MySQL. Note that in some databases user-keys would not be a valid table name and would need to be escaped (I escaped above using backticks, SQL Server would use [user-keys], etc.).
Rextester
Update:
If you want to find only staff members, then the logic is much simpler. In this case, we can just INNER JOIN the two tables together and check the status of each user:
SELECT DISTINCT
t1.userID
FROM user t1
INNER JOIN `user-keys` t2
ON t1.userID = t2.userID
WHERE t2.keyID = 2
If you want the user with keyID <> 2 you should use a inner join
SELECT u.userID
FROM users u
and u.userID not in (select userID
from `user-keys`
WHERE keyID <>2 )
You can use below code
SELECT * FROM USER WHERE ID IN
(SELECT ID FROM USER_KEY WHERE KEY_ID <> 2);
If you need all columns you can use,
SELECT * FROM USER U
INNER JOIN USER_KEY UK
ON(U.ID = UK.ID)
WHERE UK.KEYID <> 2;

Using select statement with two tables

I have two tables. One contains User and company relationship a show below
User_company
UserId CompanyId
1 2
2 1
3 1
4 2
Another table holds user information
User
Id Name City
1 Peter LA
2 Harry SF
3 John NY
4 Joe CI
How do I make a statement which will give me All the users which are in company 1? Will something like
Select * from User where Id in (Select UserId from User_company where CompanyId = 1)
work?
SELECT * from User
left join User_company on User_company.UserId=User.Id
This would work...
SELECT * works but can be sluggish over time as it may not scale well with more data.
FROM User
WHERE Id in (Select UserId from User_company where CompanyId = 1)
So would this.. - best if you need data from both tables.
SELECT *
FROM User U
INNER JOIN User_Company UC
ON U.ID = UC.UserID
WHERE UC.CompanyID = 1
As would this - Probably the fastest if you just need data from user table.
Select * from User U
where exists (Select * from User_Company UC where U.ID = UC.UserID and CompanyID = 1)
OUTER joins are only needed if you need all records from one table and only those that match in another.
As to which is the best above: it depends on existing indexes and other requirements. Any of the above will return what's been asked for.
Try this
Select u.*
from User u
inner join User_company uc
on u.Id = uc.UserId
and uc.CompanyId = 1
BTW, what's wrong with the query you have posted? It will work as well fine. Just that it's a subquery and you better replace it with Join for performance.
Select * from User where Id in
(Select UserId from User_company where CompanyId = 1)
SELECT U.* FROM User AS U LEFT JOIN
User_company AS UC ON U.Id = UC.UserId WHERE UC.CompanyId = 1

Problem using mysql joins

I'm fairly new to mysql and I have no idea if I'm heading in the right direction but I'm having trouble with a mysql query.
I basically have a table of users
id name
---- --------
1 user1
2 user2
3 user3
4 user4
as well as a table of user attributes
id userid attribute
---- ----- ------
1 1 5
2 1 6
3 2 5
4 3 4
I want to be able to select users that have both the attribute 5 and the attribute 6, so in this case I want to return
id name
---- --------
1 user1
I tried using a join like this.
SELECT u.id, u.name FROM users u LEFT JOIN attributes a ON (a.userid = u.id) WHERE a.attribute = 5 AND a.attribute = 6
But obviously that won't work, what is the best way of doing this?
One way to do this would be to use two joins; eg:
SELECT ...
FROM users u
JOIN attributes a5 ON u.id = a5.userid AND a5.attribute = 5
JOIN attributes a6 ON u.id = a6.userid AND a6.attribute = 6
Another way is by grouping (note that I am a MS SQL person, not sure if this is the right syntax for mysql or not):
SELECT u.id, u.name
FROM users u
JOIN attributes a ON u.id = a.userid
WHERE a.attribute IN (5,6)
GROUP BY u.id, u.name
HAVING COUNT(*) = 2
SELECT u.id, u.name FROM users u
INNER JOIN attributes a1 ON u.id = a1.userid
INNER JOIN attributes a2 ON u.id = a2.userid
WHERE a1.attribute = 5 AND a2.attribute = 6
Based on your question, I don't think the other two current answers are satisfactory.
If you want to:
select users that have both the
attribute 5 and the attribute 6
The following query is one way to accomplish that:
select
*
from
users
where
id in (select userid from attributes where attribute = 5)
and
id in (select userid from attributes where attribute = 6)
Hmm, I am not much into SQL, maybe GROUP BY and HAVING will help you:)
Check out the reference: http://www.w3schools.com/sql/sql_having.asp
Changing the query like this would work:
Select all from attributes table that equals 5 or 6 and then check the users who match.
SELECT a.id, u.name
FROM attributes AS a
LEFT JOIN users AS u ON a.id = u.id
WHERE a.attribute = 5 OR a.attribute = 6