Join query returning empty as well - mysql

I have three tables (many more cols but listed important ones):
users
user_id - name
1 DAN
2 TED
3 SAM
list_shares
list_shares_id - user_id - list_id
1 1 123
2 3 123
3 2 456
list_contribute
list_contr_id - list_id - can_contribute
1 123 3
I want to show all users who are in table list_shares under a list_id, join that with users table to get user info, and also count how many of them are also in the contribute table
Basically - a user can share a list with users and also invite some of the users to contribute, but not all those sharing are allowed to contribute, hence the separate list_contribute table.
here's what I'm using firstly which just shows all users with a certain ID:
select u.name, u.live_prof_pic, u.url, u.user_id from list_shares ls
join users u on ls.user_id = u.user_id
where ls.list_id = '123'
This brings up two results, which is correct - the next query is trying to find which of these two are in the list_contribute table also - but, it reduces the result to one whereas i want it to return both and show 0 for how_many if not in list_contribute
select u.name, u.live_prof_pic, u.url, count(ls.list_shares_id) as how_many, u.user_id from list_shares ls
join users u on ls.user_id = u.user_id
left join list_contribute lc on ls.list_id = lc.list_id
where ls.list_id = '123'
In the above data i want to return
user_id name how_many
3 SAM 1
1 DAN 0

Add a GROUP BY to make it a standard SQL aggregate
select u.name, u.live_prof_pic, u.url, count(ls.list_shares_id) as how_many, u.user_id
from
list_shares ls
join users u on ls.user_id = u.user_id
left join list_contribute lc on ls.event_id = lc.event_id
where ls.list_id = '123'
group by u.name, u.live_prof_pic, u.url, u.user_id
MySQL has a rubbish extension that tries to remove the requirement but gives incorrect data often
Edit, after comment.
You should still use correct GROUP BY syntax
However, your COUNT should be COUNT(lc.event_id) to count child rows.

Use query below if it does not return desired result set, it means you have orphaned record sets in list_shares which does not have corresponding users.
select
u.name
, u.user_id
, count(lc.list_id) as how_many
from
list_shares ls
INNER JOIN
users u
on
ls.user_id = u.user_id
left join
list_contribute lc
on
ls.list_id = lc.list_id
where
ls.list_id = '123'
GROUP BY
u.name
, u.user_id
Not sure how mysql count works so to be 100% sure:
select
u.name
, u.user_id
, SUM(CASE WHEN lc.list_id IS NOT NULL THEN 1 ELSE 0 END CASE) as how_many
from
list_shares ls
INNER JOIN
users u
on
ls.user_id = u.user_id
left join
list_contribute lc
on
ls.list_id = lc.list_id
where
ls.list_id = '123'
GROUP BY
u.name
, u.user_id

If I got you right - here's what you need
SQL Fiddle Example
select
u.user_id, u.name,
count(case when lc.can_contribute = u.user_id then 1 else null end) as HowMany
from users as u
inner join list_shares as ls on ls.user_id = u.user_id
inner join list_contribute as lc on lc.list_id = ls.list_id
group by
u.user_id, u.name

Related

SQL query to find all users, User 'A' follows and then check if another User 'B' also follows the same users

I want to display all users data, who User 'A' is following. And then further check if User 'B' is also following some users of User 'A'.
I managed to get al users data, who User 'A' is following. But don't understand how to query for the second condition.
Here is my Fiddle link with an example: https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=29a7d1e29f794a8f18a89fe45c06eaa9
You can try to let your User 'B' in a subquery then do OUTER JOIN
SELECT u.*,
IF(friend_id IS NULL,0,1) amIfollowing
FROM users u
LEFT JOIN (
Select friend_id
from friends
where user_id = 5
) f ON f.friend_id = u.id
WHERE u.id IN (SELECT f.friend_id
FROM friends f
WHERE f.user_id = 1)
ORDER BY u.id
sqlfiddle
If I understand correctly you can try to use only one subquery for friends and then use the condition aggregate function to get the result.
SELECT u.id,
u.image_width,
MAX(CASE WHEN f.user_id = 5 THEN 1 ELSE 0 END) amIfollowing
FROM users u
JOIN (
Select friend_id,user_id
from friends
where user_id IN (1,5)
) f ON f.friend_id = u.id
GROUP BY u.id,
u.image_width
ORDER BY u.id
You could use exists here to check if the corresponding IDs exist:
SELECT *,
case when exists (
select * from friends f
where f.friend_id = u.id and f.user_id = 5
) then 1 else 0 end amIfollowing
FROM users u
WHERE u.id IN (SELECT f.friend_id
FROM friends f
WHERE f.user_id = 1);
Example Fiddle
Looks like a JOIN will do, with distinct
SELECT distinct u.*, (f2.user_Id is not null) amIfollowing
FROM users u
JOIN friends f ON u.id = f.friend_id
LEFT JOIN friends f2 on f2.friend_id = f.friend_id and f2.user_id = 5
WHERE f.user_id = 1
ORDER BY u.id

Return multiple data with condition from multiple tables in mysql

I am having problem with fetching data from multiple tables with some conditions in MySQL.
I have follwing three tables:
Like Table
Like_id photoID userID
1 1 1
2 2 2
3 2 1
BookMark Table
bookmark_id photoID userID
1 1 1
2 2 2
3 2 1
Users Table
User_id Name Email
1 Max B maxb#gmailcom
2 Tom Smith toms#gmailcom
CONDITIONS:
At first i want to check whether there is any data from the LIKE table for the userID = 2. If there is no data it should return "false" otherwise it should return "true".
Similarly, i want to check whether there is any data from the BOOKMARK table for the userID = 2. If there is no data it should return "false" otherwise it should return "true".
Finally, i want to fetch the Name and Email from the USERS table for the userID = 2.
WANTED:
I want to achieve all these information in a SINGLE QUERY with the above mentioned conditions from these three tables.
SO FAR tried with this QUERY:
select Like.Like_id from (Like left join Users on Like.userID = Users.User_id)
left join BookMark on Users.User_id = BookMark.bookmark_id
where Users.User_id = 2
With #Gervs suggestion:
SELECT
u.user_id,
u.name,
u.email,
(CASE WHEN ISNULL(l.user_id) THEN 'false' ELSE 'true' END) AS 'likes',
(CASE WHEN ISNULL(b.user_id) THEN 'false' ELSE 'true' END) AS 'bookmarks'
FROM
users u
LEFT JOIN
likes l
ON u.user_id = l.user_id
LEFT JOIN
bookmarks
ON u.user_id = b.user_id
WHERE u.user_id = 2
GROUP BY u.user_id
What will be the easiest but efficient single query to fetch these information?
Will VIEW be a best option for these conditions?
Advanced thanks for your participation.
You can inner join both like table and bookmark table on users table, that is if you want only users that have entries in both tables.
SELECT
u.user_id,
u.name,
u.email,
COUNT(l.user_id) likes,
COUNT(b.user_id) bookmarks
FROM
users u
JOIN
likes l
ON u.user_id = l.user_id
JOIN
bookmarks b
ON u.user_id = b.user_id
WHERE u.user_id = 2
GROUP BY u.user_id
If you always want the user, just change the inner joins into left joins and likes and/or bookmarks will be zero if no entries are found
SELECT
u.user_id,
u.name,
u.email,
CASE WHEN COUNT(l.user_id) > 0 THEN 'true' ELSE 'false' END likes,
CASE WHEN COUNT(b.user_id) > 0 THEN 'true' ELSE 'false' END bookmarks
FROM
users u
LEFT JOIN
likes l
ON u.user_id = l.user_id
LEFT JOIN
bookmarks b
ON u.user_id = b.user_id
WHERE u.user_id = 2
GROUP BY u.user_id

Find out if user exists in a sum when joining multiple tables

I've got 3 tables:
submissions, submissions_votes, and users. My current query:
SELECT s.*, u.username, u.avatar, SUM(sv.up) helpfulVotes
FROM submissions s
INNER JOIN users u
ON s.user_id = u.id
LEFT JOIN submissions_votes sv
ON s.id = sv.submission_id
WHERE s.id = 23
GROUP BY s.id
Will return for me the submission details, the user who submitted it, and the amount of helpfulVotes on the submission (which comes from the submissions_votes table).
This works fine, but what I'd like to do is test for a condition within the SUM(sv.up) to see if the any of the users within that sum matches a particular user_id from submissions.
I was thinking of doing something like this but it doesn't work:
SELECT s.*, u.username, u.avatar, SUM(sv.up) helpfulVotes,
SUM (IF(sv.user_id = 15, count, 1)) as currentUserVoted, <---- ???
FROM submissions s
INNER JOIN users u
ON s.user_id = u.id
LEFT JOIN submissions_votes sv
ON s.id = sv.submission_id
WHERE s.id = 23
GROUP BY s.id
How can I see if there is a match within that sum to the current user's id (in this case, 15)?
Yes you can use condition in SUM() just like SUM (sv.user_id = 15) will give you the count for user 15
SELECT
s.*,
u.username,
u.avatar,
SUM(sv.up) helpfulVotes,
SUM(sv.user_id = 15) AS currentUserVoted
FROM
submissions s
INNER JOIN users u
ON s.user_id = u.id
LEFT JOIN submissions_votes sv
ON s.id = sv.submission_id
WHERE s.id = 23
GROUP BY s.id
or if you want to sum another column based on user id you can use CASE
SUM (CASE WHEN sv.user_id = 15 THEN sum_other_col ELSE 0 END) as currentUserVoted

Select the users are not friend of a specific user

Hi, I have these two tables: users and friends (friend_status = 1 means the request is sent, friend_status = 2 means they are friends). Now I want to select all users are not friend of a specific user. How to do?
Assuming the current user is 1. I tried this SQL. It works but it's too long and slow. The first selects all users sent request to user1 but not accepted. The second selects all users receive request from user1. The third and the fourth selects all users is not in "friends" table.
SELECT user_id, name, email
FROM
(
SELECT user_id, name, email
FROM users u INNER JOIN friends f ON u.user_id = f.sender
WHERE f.receiver = 1 AND friend_status <> 2
UNION
SELECT user_id, name, email
FROM users u INNER JOIN friends f ON u.user_id = f.receiver
WHERE f.sender = 1 AND friend_status <> 2
UNION
SELECT u.user_id, u.name, u.email
FROM users u LEFT JOIN friends f ON u.user_id = f.sender
WHERE f.receiver IS NULL
GROUP BY user_id
UNION
SELECT u.user_id, u.name, u.email
FROM users u LEFT JOIN friends f ON u.user_id = f.receiver
WHERE f.sender IS NULL
GROUP BY user_id
) T
GROUP BY user_id
Update: Add a pic.
SELECT
a.user_id,
a.name,
a.email,
b.status IS NOT NULL AS friend_status
FROM
users a
LEFT JOIN
friends b ON
a.user_id IN (b.sender, b.receiver) AND
1 IN (b.sender, b.receiver)
WHERE
(b.friend_id IS NULL OR b.status <> 2) AND
a.user_id <> 1
You had asked a question previously here - "Select users who aren't friends with anyone", and I provided an answer which utilized a LEFT JOIN.
Building off of that, to select users who aren't friends with a specific user, we just simply need to add that specific user's ID to the LEFT JOIN condition (1 IN (b.sender, b.receiver).
Minor Edit: Unless the user can friend him/herself, it wouldn't make sense to also select the user who we're selecting against!! So I added WHERE a.user_id <> 1.
Assuming you want to perform the query on user_id 1:
SELECT user_id, name, email
FROM users AS u
WHERE NOT EXISTS (SELECT * FROM friends AS f
WHERE (f.sender = u.user_id AND f.receiver = 1 AND f.friend_status = 2)
OR (f.sender = 1 AND f.receiver = u.user_id AND f.friend_status = 2)
)
AND u.user_id <> 1
The subquery fetches all the established friendship relationship in which user 1 is either the sender or the receiver. The outer query selects all users for which no such relationship exists. The user with ID 1 is excluded from the query using the last line, as, even if he cannot be friend with himself, I suppose that he should not appear in the final query result.
You may be able to simplify this by using something like this:
SELECT user_id, name, email
FROM
(
SELECT u.user_id, u.name, u.email
FROM users u LEFT JOIN friends f ON u.user_id = f.sender
WHERE IFNULL(friend_status,0) <> 2
GROUP BY user_id
UNION
SELECT u.user_id, u.name, u.email
FROM users u LEFT JOIN friends f ON u.user_id = f.receiver
WHERE IFNULL(friend_status,0) <> 2
GROUP BY user_id
) T
GROUP BY user_id
The IFNULL function returns the value of the first parameter, replacing NULLs with the value of the value second parameter. In this case it means that friend_status will be treated as 0 if there is no matching friend in the friends table, which allows you to reduce the number of selects in the UNION by half.
Try this query
select
u.user_id,
u.name,
u.email,
ifnull(f.friend_status,0) as Relation
from users as u
left join friends as f
on f.sender = u.user_id
where u.user_id not in(select
sender
from friends
where sender = 1)
Here sender = 1 means the user id = 1. You can pass user id to restrict this condition. Also status 0 means he is not friend. and 1 , 2 , 3 are according to your rules

Left Join 2 tables on 1 table

It must be pretty easy, but i can't think of any solution nor can I find an answer somewhere...
I got the table 'users'
and one table 'blogs' (user_id, blogpost)
and one table 'messages' (user_id, message)
I'd like to have the following result:
User | count(blogs) | count(messages)
Jim | 0 | 3
Tom | 2 | 3
Tim | 0 | 1
Foo | 2 | 0
So what I did is:
SELECT u.id, count(b.id), count(m.id) FROM `users` u
LEFT JOIN blogs b ON b.user_id = u.id
LEFT JOIN messages m ON m.user_id = u.id
GROUP BY u.id
It obviously doesn't work, because the second left join relates to blogs not users. Any suggestions?
First, if you only want the count value, you could do subselects:
select u.id, u.name,
(select count(b.id) from blogs where userid = u.id) as 'blogs',
(select count(m.id) from messages where userid = u.id) as 'messages'
from 'users'
Note that this is just a plain sql example, I have no mysql db here to test it right now.
On the other hand, you could do a join, but you should use an outer join to include users without blogs but with messages. That would imply that you get several users multiple times, so a group by would be helpful.
If you use an aggregate function in a select, SQL will collapse all your rows into a single row.
In order to get more than 1 row out you must use a group by clause.
Then SQL will generate totals per user.
Fastest option
SELECT
u.id
, (SELECT(COUNT(*) FROM blogs b WHERE b.user_id = u.id) as blogcount
, (SELECT(COUNT(*) FROM messages m WHERE m.user_id = u.id) as messagecount
FROM users u
Why you code does not work
SELECT u.id, count(b.id), count(m.id)
FROM users u
LEFT JOIN blogs b ON b.user_id = u.id <<-- 3 matches multiplies # of rows *3
LEFT JOIN messages m ON m.user_id = u.id <<-- 5 matches multiplies # of rows *5
GROUP BY u.id
The count will be off, because you are counting duplicate items.
Simple fix, but will be slower than option 1
If you only count distinct id's, you will get the correct counts:
SELECT u.id, count(DISTNICT b.id), count(DISTINCT m.id)
FROM users u
LEFT JOIN blogs b ON b.user_id = u.id
LEFT JOIN messages m ON m.user_id = u.id
GROUP BY u.id