SQL join 3 tables while getting count from 2 of them - sql

Back with another SQL question about joins. I have 3 tables:
user: id, username, name, city, state, private
rides: id, creator, title, datetime, city, state
posts: id, title, user, date, state, city
I need to get the users from the user table, and based on the id of user, get the number of posts and rides for each person. Such as, user with id 25 has 2 rides and 4 posts, while the user with id 27 has 2 rides and 2 posts. The problem I am having, is that both users are coming back with 4 posts and rides each.
user.id = rides.creator = posts.user //just so you know what fields equals the user id
Here is my code:
select u.id, u.username, u.state, u.city, count(p.id) as TotalPosts, count(r.id) as TotalRides
from user u
left join posts p on p.user=u.id
left join rides r on r.creator=u.id
where private='public'
group by u.id
order by u.username, u.state asc;
If I separate them out, and just join the posts or the rides, I get the correct totals back. I tried switching the order of the joins, but I got the same results. Not sure what is going on.
Any ideas or thoughts are appreciated.

Your problem is a Cartesian product along two different dimensions. The best solution is to pre-aggregate the data:
select u.id, u.username, u.state, u.city, p.TotalPosts, r.TotalRides
from user u left join
(select user, count(*) as totalposts
from posts p
group by user
) p
on p.user = u.id left join
(select creator, count(*) as totalrides
from rides r
group by creator
) r
on r.creator = u.id
where u.private = 'public'
group by u.id
order by u.username, u.state asc;

you can always use a sub select.
select u.*,
(select count(*) from posts where user = u.id) as 'posts',
(select count(*) from rides where creator = u.id) as 'rides'
from users u
where .....

Related

Distinct Count with data from another table

I have 4 tables
All ID related things are ints and the rest are texts.
I want to count the number of albums the user is tagged at so if a user is tagged in album1 once album2 once and album3 once it will show 3 and if more in any of them it will still show 3.
I tried to do:
SELECT COUNT(DISTINCT ALBUM_ID) FROM PICTURES WHERE ID=(SELECT PICTURE_ID FROM TAGS WHERE USER_ID=userId);
But this returned 1 although it was supposed to return 3 and the same happened without DISTINCT.
How can I get the amount?
EDIT:
I want to check only one user(I have the user's ID and name)
You must join users with LEFT joins to tags and pictures and aggregate:
SELECT u.id, u.name, COUNT(DISTINCT p.album_id) counter
FROM users u
LEFT JOIN tags t ON t.user_id = u.id
LEFT JOIN pictures p ON p.id = t.picture_id
GROUP BY u.id, u.name
If you want the result for a specific user only:
SELECT u.id, u.name, COUNT(DISTINCT p.album_id) counter
FROM users u
LEFT JOIN tags t ON t.user_id = u.id
LEFT JOIN pictures p ON p.id = t.picture_id
WHERE u.id = ?
GROUP BY u.id, u.name -- you may omit this line, because SQLite allows it
Or with a correlated subquery:
SELECT u.id, u.name,
(
SELECT COUNT(DISTINCT p.album_id)
FROM tags t INNER JOIN pictures p
ON p.id = t.picture_id
WHERE t.user_id = u.id
) counter
FROM users u
WHERE u.id = ?
Replace ? with the id of the user that you want.

Only show users that having cars more than one

Dear all I have users table and cars table.
and I have following join query:
select
users.id as user_id,
users.username,
users.job,
cars.id,
cars.brand as car_brand
FROM users
LEFT JOIN cars on users.id = cars.user_id
GROUP BY users.username, users.id, cars.id;
Here is the snapshot:
How to query for users that having cars more than one?
I tried code below but it return empty data:
How to get users that having more than one cars? (username: Ismed)
You can do in this was as well.
select
users.id as user_id,
users.username,
users.job,
cars.id,
cars.brand as car_brand
FROM users
LEFT JOIN cars on users.id = cars.user_id
where exists (select username, count(*) multiplecars
FROM users u
JOIN cars c on u.id = c.user_id
where users.username = u.username
group by
u.username
having count(*) > 1 )
If the users have more than one car (even if same brand then this will bring those records) if you only want users with more than one branded care you can do count(distinct)
The simplest and probably most performance method is to use window functions:
select user_id, username, job, id, brand
from (select u.id as user_id, u.username, u.job,
c.id, c.brand as car_brand,
count(*) over (partition by u.id) as num_cars
from users u join
cars c
on u.id = c.user_id
) uc
where num_cars > 1;
Note that I changed the left join to a join. If you have two matches, you are requiring a match. I also introduced table aliases so the query is easier to write and to read.
SELECT users.username
FROM users
WHERE users.id IN(
select
users.id
FROM users
JOIN cars on users.id = cars.user_id
GROUP BY users.id
HAVING COUNT(*) > 1
);
Filter users first who has more then one car then get corresponding details

SQL query to find the top 3 in a category

Calling all sql enthusiasts!
Quick info: using PostgreSQL.
I have a query that return the maximum number of likes for a user per category. What I want now, is to show the top 3 users with the most likes per category.
A helpful resource was using this example to solve the problem:
select type, variety, price
from fruits
where (
select count(*) from fruits as f
where f.type = fruits.type and f.price <= fruits.price
) <= 2;
I understand this, but my query is using joins and I am also a beginner, so I was not able to use this information effectively.
Down to business, this is my query for returning the MAX likes for a user per category.
SELECT category, username, MAX(post_likes) FROM (
SELECT c.name category, u.username username, SUM(p.like_count) post_likes, COUNT(*) post_num
FROM categories c
JOIN topics t ON c.id = t.category_id
JOIN posts p ON t.id = p.topic_id
JOIN users u ON u.id = p.user_id
GROUP BY c.name, u.username) AS leaders
WHERE post_likes > 0
GROUP BY category, username
HAVING MAX(post_likes) >= (SELECT SUM(p.like_count)
FROM categories c
JOIN topics t ON c.id = t.category_id
JOIN posts p ON t.id = p.topic_id
JOIN users u ON u.id = p.user_id WHERE c.name = leaders.category
GROUP BY u.username order by sum desc limit 1)
ORDER BY MAX(post_likes) DESC;
Any and all help would be greatly appreciated. I am having a difficult time wrapping my head around this problem. Thank!
If you want the most likes per category, use window functions:
SELECT cu.*
FROM (SELECT c.name as category, u.username as username,
SUM(p.like_count) as post_likes, COUNT(*) as post_num,
ROW_NUMBER() OVER (PARTITION BY c.name ORDER BY COUNT(*) DESC) as seqnum
FROM categories c JOIN
topics t
ON c.id = t.category_id JOIN
posts p
ON t.id = p.topic_id JOIN
users u
ON u.id = p.user_id
GROUP BY c.name, u.username
) cu
WHERE seqnum <= 3;
This always returns three rows per category, even if there are ties. If you want to do something else, then consider DENSE_RANK() or RANK() instead of ROW_NUMBER().
Also, use as for column aliases in the FROM clause. Although optional, one day you will leave out a comma and be grateful that you are in the habit of using as.

SQL query for showing total votes per user in SO-like system

Consider a simplified table schema of a StackOverflow-like system:
Tables:
User ( id, name )
Question ( id, user_id, question )
Vote ( id, question_id )
How would I write a SQL query that would
List each user along with the total votes for all his questions, ordered by most votes?
Given a user_id, return a single user record, along with his total votes?
User Name | Total Votes (desc)
select User.id,
User.name,
count(vote.id) as Votes
from User
left join Question
on User.id = Question.user_id
left join Vote
on Vote.question_id = Question.id
group by user.id, User.name
order by 3 desc
For your first question:
SELECT u.name, COUNT(v.id) AS TotalVotes
FROM User u
LEFT JOIN Question q
INNER JOIN Vote v
ON q.id = v.question_id
ON u.id = q.user_id
GROUP BY u.name
ORDER BY TotalVotes DESC
For your second question:
SELECT u.name, COUNT(v.id) AS TotalVotes
FROM User u
LEFT JOIN Question q
INNER JOIN Vote v
ON q.id = v.question_id
ON u.id = q.user_id
WHERE u.id = #GivenUserId
GROUP BY u.name
SELECT user.name, question.question, count(vote.id) votes
FROM user
inner join question on user.id=question.user_id
inner join vote on question.id=vote.question_id
GROUP BY user.name, question.question
ORDER BY votes

SQL: Finding user with most number of comments

I need to find out the user who has posted the most number of comments. There are two tables 1)users(Id, DisplayName) 2)comments(Id, UserId, test) . I have used the following query
Select DisplayName from users INNER JOIN (Select UserId, max(comment_count) as `max_comments from (Select UserId, count(Id) as comment_count from comments group by UserId) as` T1) as T2 ON users.Id=T2.UserId
However, this returns to me the Display Name of the user with Id = 1 rather than what I want. How do I work around this ?
SELECT TOP 1
U.DisplayName,
COUNT(C.ID) AS CommentCount
FROM
Users AS U
INNER JOIN Comments AS C ON U.ID = C.UserID
GROUP BY
U.DisplayName
ORDER BY
COUNT(C.ID) DESC