MySQL - how to combine three tables to get the counts - mysql

There are three tables, I would like to get the count of a user's total tweets and the count of likes his total tweets received.
I tried to combine two queries to get what I want but failed. Have looked through several previous questions but still can't figure it out.
Users table
id
name
1
User1
Tweets table
id
UserId (foreign key)
content
1
User1
hello
Likes table
id
UserId (foreign key)
TweetId (foreign key)
1
User1
hello
First query:
SELECT Users.name, Users.id, COUNT(Tweets.UserId) AS UserTweetCount FROM Users
LEFT JOIN Tweets
ON Users.id = Tweets.UserId
GROUP BY Users.id
ORDER BY UserTweetCount DESC;
Second query:
SELECT Users.name, Users.id, COUNT(Likes.UserId) AS UserTweetBeLikedCount FROM Users
LEFT JOIN Likes
ON Users.id = Likes.UserId
GROUP BY Users.id;
I tried like below but would get wrong UserTweetBeLikedCount counts. The counts would be UserTweetCount's, not UserTweetBeLikedCount's. When I ran two queries separately, it worked well. But when I combined them together, it didn't work right.
Don't know how to display the right counts. Can someone give me hints to solve this, please?
SELECT Users.name, Users.id,
COUNT(Tweets.UserId) AS UserTweetCount, COUNT(Likes.UserId) AS UserTweetBeLikedCount
FROM Users
LEFT JOIN Tweets
ON Users.id = Tweets.UserId
LEFT JOIN Likes
ON Users.id = Likes.UserId
GROUP BY Users.id
ORDER BY UserTweetCount DESC;

I recommend using correlated subqueries for this:
SELECT u.*,
(SELECT COUNT(*)
FROM Tweets t
WHERE u.id = t.UserId
) AS UserTweetCount,
(SELECT COUNT(*)
FROM Likes l
WHERE u.id = l.UserId
) AS UserLikeCount
FROM Users u
ORDER BY UserTweetCount DESC;
As a note: For performance, you want indexes on Tweets(UserId) and Likes(UserId).

Related

Order by subquery table

I have the following query:
SELECT users.id, username FROM users
where exists (select 1 from topic_visits tv where users.id = tv.user_id and topic_id = 2)
order by tv.created_at;
I want to retrieve all users who have visited topic 2 in ascending order (oldest visit first).
I got this error: #1054 - Unknown column 'tv.created_at' in 'order clause'.
You can change your query as shown below:
SELECT distinct users.id, username,tv.created_at
FROM users
join topic_visits tv ON users.id = tv.user_id and topic_id = 2
order by tv.created_at
tv is in the sub-query, it doesn't exist at the top level.
using a join, we group by users.id so there is a unique list of users.
As the tv.created_at could be multiple we need to wrap it in an aggregate function, in this case MAX. Maybe MIN suites your needs better however.
SELECT users.id, username
FROM users
join topic_visits tv ON users.id = tv.user_id and topic_id = 2
group by users.id
order by MAX(tv.created_at);

Counting and Summing three tables together and get users information with their like counts

I have three tables:
table: users / columns: user_id, email, username
table: activities / columns: object, type, like_count
table: activities2 / columns: object, target_type, subject, type
The like_count in activities table has no problem and I count all of that with this query:
SELECT SUM(activities.like_count) AS likes, users.user_id, users.email, users.username
FROM activities
INNER JOIN users
ON activities.subject = users.user_id
GROUP BY user_id
But there is another count in activities table which is being inserted(NOT UPDATED) each time some other types of posts liked and I counted them by this query:
SELECT activities.subject, activities.object, COUNT(activities.type) AS likes
FROM activities
INNER JOIN activities2
ON activities.object = activities2.object AND activities2.target_type = 'parent'
WHERE activities2.type LIKE 'like_%'
GROUP BY activities2.subject
BUT the problem starts from here when I want to join them together! I want to count like_count + count of likes that inserted in that table(activities2) that contains string of 'like_' and beside this I want to join the subject(in activities table) which is related to user_id in the other table(users).
My last query is this:
SELECT users.user_id, users.email, users.username, activities.object, COUNT(activities.type)+SUM(activities.like_count) AS likes
FROM activities
INNER JOIN activities2
ON activities.object = activities2.object AND activities2.target_type = 'parent'
INNER JOIN users
ON activities.subject = users.user_id
WHERE activities2.type LIKE 'like_%'
GROUP BY users.user_id
The problem is when joining, it fetches the user information not for the one that I want.
In conclusion I want something like this:
user_id------email-----------------username----------object-------likes
2521---------a#b.com---------------abc---------------9578---------3
5484---------c#d.com---------------def---------------8547---------16
8431---------e#f.com---------------ghi---------------4584---------1
And offcourse the result is this but only likes are correct however columns of user_id, email, username that are in users table NOT!
I was wondering if you would help to fix it. I'm really tired of trying and facing to no result :(
users table data:
user_id-------------email---------------username
1-------------------a#b.com-------------abc
2-------------------c#d.com-------------def
3-------------------e#f.com-------------ghi
activities table data:
object----------type----------------like_count------subject
20--------------like_video----------0---------------1
20--------------like_photo----------0---------------2
33--------------like_music----------0---------------3
33--------------some_other_type-----5---------------6
33--------------some_other_type-----8---------------10
activities2 table data:
object------target_type-----subject-----type
20----------parent----------30----------like_video
21----------owner-----------40----------like_audio
22----------parent----------50----------something_not_start_with_like_
I want:
user_id------email-----------------username----------object-------likes
1------------a#b.com---------------abc---------------9578---------(sum of like_count + count of type which has like_ in first characters)
2------------c#d.com---------------def---------------8547---------(sum of like_count + count of type which has like_ in first characters)
3------------e#f.com---------------ghi---------------4584---------(sum of like_count + count of type which has like_ in first characters)
Consider joining the aggregate queries using derived tables and then run your addition calculation in the outer query. Also, below object column is removed from the second aggregate query's GROUP BY clause but still used in JOIN since you need summation at the subject level.
SELECT u.user_id, u.email, u.username, a.`object`, u.likes + a.likes as `total_likes`
FROM
(SELECT SUM(activities.like_count) AS likes, users.user_id, users.email, users.username
FROM activities
INNER JOIN users
ON activities.subject = users.user_id
GROUP BY user_id, users.email, users.username) u
INNER JOIN
(SELECT activities.subject, COUNT(activities.type) AS likes
FROM activities
INNER JOIN activities2
ON activities.object = activities2.object AND activities2.target_type = 'parent'
WHERE activities2.type LIKE 'like_%'
GROUP BY activities2.subject) As a
ON u.user_id = a.subject

How to format this MySQL query?

I have a table posts with columns board_id, author_id, message. I have another table users with columns id, name, avatar_url.
I need to write a query to get all of the users that have posted on a given board, with no duplicates. The query should return the full user row (id, name, avatar_url).
I've tried
SELECT DISTINCT users.*, posts.author_id
FROM users
INNER JOIN posts
ON users.id = posts.author_id
WHERE posts.board_id = [desired board ID]
but that's giving me duplicates of each user.
There is also the possibility that my query is correct and I've goofed on something elsewhere...
Here's a simple query that will get you all the rows in users with post activity w/o duplication
SELECT * FROM USERS
WHERE id IN (SELECT author_id FROM posts WHERE board_id = [desired board]
You could also use your basic syntax with a distinct on everything you need distinct, e.g.:
SELECT DISTINCT users.*
FROM users
JOIN posts ON users.id = posts.author_id
WHERE posts.board_id = [desired board ID]
Just group by the user id, like so:
SELECT users.id, MIN(users.name), MIN(users.avatar_url)
FROM users
INNER JOIN posts
ON users.id = posts.author_id
WHERE posts.board_id = [desired board ID]
GROUP BY users.id
SELECT users.id, users.name, users.avatar_url, posts.author_id
FROM users
INNER JOIN posts
ON users.id = posts.author_id
WHERE posts.board_id = [desired board ID] GROUP BY users.id
This will get all found rows and then group them by the userid so each user id will appear just once, hence each user row [who posts on the board] will appear just once.
Yet better is use with annotation not for highlighted after IN, which defense against duplicate values. That's it.

How to join 3 tables and get sum from result of individual joins?

I have the following scenario:
Table: users : user_id, username ,...
Table: login: user_id, login_date, ...
Table: point: user_id, points, point_time
Joins will be on the basis of users.user_id with other tables.
Now, I want to get count of all the logins as well as sum of all the points earned by the user.
Now, when I do:
select users.user_id,count(*) from users
inner join login on users.user_id=login.user_id
group by users.user_id
It returns count as 36(for example).
Whenever I run:
select users.user_id,count(*),sum(points) from users
inner join point on users.user_id=point.user_id
group by users.user_id
It returns sum as 400(for example) and count as 2.
But if I combine both the queries:
select users.user_id,count(*),sum(points) from users
inner join login on users.user_id=login.user_id
inner join point on users.user_id=point.user_id
group by users.user_id
It returns count as 72 (36 * 2) and sum as 800 (400 *2).
Twice because of multiple userIds present.
I tried several things like combining with distincts but nothing seems to work. Please help.Better if it's possible with joins alone. Thanks in advance. I am using mysql with Php.
You can sum the points in a subquery and select distinct logins in the count
select users.user_id,l.login,p.points from users
inner join (select user_id, count(1) login from login
group by login) as l on users.user_id=login.user_id
inner join (select user_id, sum(point) as point
from point group by user_id ) as p on users.user_id=point.user_id
You should be able to do your count by joining in your login table and then including a subquery to get your count of points:
select users.user_id, count(*) as login_count,
(select sum(points) from point
where point.user_id = users.user_id) as points_sum
from users
inner join login on users.user_id=login.user_id
group by users.user_id

Order by 2 values, using 3 tables

Sorry if this is a silly question, I searched a bit and couldn't find a solution for an example like mine.
I've got a small photo sharing app with a query which outputs the ID numbers of users, ordered by the number of followers they have. I want to alter the query slightly so that if users have the same number of followers, they will be ordered by the number of photos they've uploaded instead.
How would I go about editing my query? All attempts I've made have been unsuccessful.
Current query looks like this:
SELECT Users.ID, COUNT(User_Followers.FollowingUserID)
AS follower_count FROM Users
LEFT JOIN User_Followers ON Users.ID = User_Followers.FollowingUserID
GROUP BY Users.ID
ORDER BY follower_count DESC
Where the User_Followers table looks like this:
ID UserID FollowingUserID DateFollowed
And the photos table looks like this:
ID PostedByUserID DatePosted
Thanks in advance for any help!
SELECT Users.ID,
COUNT(User_Followers.FollowingUserID) AS follower_count
FROM Users
LEFT JOIN User_Followers
ON Users.ID = User_Followers.FollowingUserID
LEFT JOIN
(
SELECT PostedByUserID, COUNT(*) postCount
FROM photos
GROUP BY PostedByUserID
) a ON Users.ID = a.PostedByUserID
GROUP BY Users.ID
ORDER BY follower_count DESC, a.postCount DESC