I've been fiddleing with this about 20 minutes now and though I might get some help here. I have two tables, in a many-to-one relationship. users (one) and events (many). The tables, simplified, look like this:
users
-----------
user_id
group_id
events
-----------
user_id
I'm trying to produce a report that will show the number of users with at least one event, per group. so a result set would hopefully look like:
group_id users_with_at_least_one_event
1 689
2 312
SELECT group_id, count(*) users_with_at_least_one_event
FROM
(
SELECT u.user_id, u.group_id, count(*) as event_count
FROM users u
JOIN events e
ON u.user_id = e.user_id
GROUP BY u.user_id, u.group_id
HAVING count(*) > 1
) sub
GROUP BY group_id
SELECT group_id, COUNT(users.user_id) AS users_with_at_least_one_event,
FROM users, events
WHERE users.user_id = events.user_id
GROUP BY group_id
maybe?
try
select users.group_id, count(distinct users.user_id) as users_with_at_least_one_event
from
users, events
where users.user_id = events.user_id
group by users.group_id
SELECT users.group_id, COUNT(*) FROM users
WHERE users.user_id IN (SELECT events.user_id FROM events)
Related
I have 4 tables called shops, users, review and rating.
I want to get all reviews for the corresponding shop with reviewed user details and also overall rating for that shop.
I have done almost with the single query. But the problem is if the shop has same rating for multiple times by same user its consider as single rating. But that rating count was correct.
i.e
from this table user_id 3 was rated shop_id 1 as 4 times. So the count is 4 and total_rating is 17.
My query is
select review.comments, users.username, count(distinct rating.id) as rating_count,
sum(distinct rating.rating) as total_rating from users
left join review on users.id = review.user_id and review.shop_id='1'
left join rating on users.id = rating.user_id and rating.shop_id='1'
where review.shop_id='1' or rating.shop_id='1'
group by users.id, review.user_id, rating.user_id, review.id
When I run this query I got
But I need total_rating 17 for user_id 3..
Check this fiddle
You put DISTINCT IN sum( rating.rating) as total_rating, thats why the result(12=17-5), since it will include 5 only once while computing sum.
select review.comments, review.user_id, count(distinct rating.id) as rating_count,
sum( rating.rating) as total_rating from users
left join review on users.id = review.user_id and review.shop_id='1'
left join rating on users.id = rating.user_id and rating.shop_id='1'
where review.shop_id='1' or rating.shop_id='1'
group by users.id, review.user_id, rating.user_id, review.id
Here is SQLFiddle
Sample Output :
Hope this helps
Try this - Remove the distinct from sum(rating.rating). Since you gave sum(distinct rating.rating), it is ignoring one 5 that user 3 gave to store 1.
select review.comments, users.username, count(distinct rating.id) as rating_count,
sum(rating.rating) as total_rating from users
left join review on users.id = review.user_id and review.shop_id='1'
left join rating on users.id = rating.user_id and rating.shop_id='1'
where review.shop_id='1' or rating.shop_id='1'
group by users.id, review.user_id, rating.user_id, review.id
First of all: It makes no sense to outer-join records from a table and then remove them in the WHERE clause. With left join review ... you say: find a matching record in table review, and if you don't find any, then add nulls, so we keep the users record. Then with where review.shop_id='1' you say: keep only records where you actually found a record in review. So you are dismissing the records that you just took the pain to keep. Your WHERE clause renders your LEFT OUTER JOINS mere INNER JOINS.
As to your actual problem: That stems from joining all tables first and only then trying to get aggregates from the resulting records. Aggregate before joining instead:
select
rev.comments,
usr.username,
coalesce(rat.rating_count, 0) as rating_count,
rat.total_rating
from review rev
join users usr on users.id = review.user_id
left join
(
select user_id, shop_id, count(*) as rating_count, sum(rating) as total_rating
from rating
group by user_id, shop_id
) rat on rat.user_id = usr.id and rat.shop_id = rev.shop_id
where rev.shop_id = 1
group by rev.id;
I have two tables, Users(id, username) and Posts(id, user_id, content). I want to list a summary of them which, I want to list all users and the first post of each user. How can I realize this in one query?
I tried something like.
QUERY
SELECT Users.*, Posts.content
FROM Users, Posts
WHERE Posts.user_id=T_Users.id
But it will return all posts for each user (I cannot add LIMIT 1 at the tail of course which only returns one user).
Some sample records:
Users table:
id username
1 test1
2 test2
Posts table:
id user_id content
1 1 This is a test1's content.
2 1 This is another test1's content.
3 2 This is a test2's content.
And I want the result:
Users.id Users.username Posts.content
1 test1 This is a test1's content.
2 test2 This is a test2's content.
Here is one approach to get the latest record per user i assume the latest record will be considered as the minimum post id
SELECT u.*, p.content
FROM Users u
join Posts p on p.user_id=u.id
join (select user_id ,min(id) id from Posts group by user_id ) p1
on (p.id = p1.id and p.user_id = p1.user_id )
Demo
Try this
select min(x.id) as Id,x.user_id,x.content from(
select p.id,p.user_id,p.content from Users u inner join Posts p
on u.id=p.user_id and u.gender=1
)x group by x.user_id
Have you tried group by clause.
SELECT Users.*, Posts.content
FROM Users, Posts
WHERE Posts.user_id=T_Users.id GROUP BY Posts.user_id
I want to show the conclusion of all users.
I have 3 tables.
table post
post_id(index) user_id
1 1
2 3
3 3
4 4
table photo
photo_id(index) user_id
1 2
2 4
3 1
4 1
table video
photo_id(index) user_id
1 4
2 4
3 3
4 3
and in table user
user_id(index) user_name
1 mark
2 tommy
3 john
4 james
in fact, it has more than 4 rows for every tables.
I want the result like this.
id name post photo videos
1 mark 1 2 0
2 tommy 0 1 0
3 john 2 0 2
4 james 1 1 2
5 .. .. .. ..
Code below is SQL that can work correctly but very slow, I will be true appreciated if you help me how it using LEFT JOIN for it. Thanks.
SQL
"select user.*,
(select count(*) from post where post.userid = user.userid) postCount,
(select count(*) from photo where photo.userid = user.userid) photoCount,
(select count(*) from video where video .userid = user.userid) videoCount
from user order by user.id"
(or ORDER BY postCount, photoCount or videoCount ASC or DESC as i want )
I done researched before but no any helped me.
SELECT u.user_id,
u.user_name,
COUNT(DISTINCT p.post_id) AS `postCount`,
COUNT(DISTINCT ph.photo_id) AS `photoCount`,
COUNT(DISTINCT v.video_id) AS `videoCount`
FROM user u
LEFT JOIN post p
ON p.user_id = u.user_id
LEFT JOIN photo ph
ON ph.user_id = u.user_id
LEFT JOIN video v
ON v.user_id = u.user_id
GROUP BY u.user_id
ORDER BY postCount;
Live DEMO
Your method of doing this is quite reasonable. Here is your query:
select user.*,
(select count(*) from post where post.userid = user.userid) as postCount,
(select count(*) from photo where photo.userid = user.userid) as photoCount,
(select count(*) from video where video.userid = user.userid) as videoCount
from user
order by user.id;
For this query, you want the following indexes:
post(userid)
photo(userid)
video(userid)
user(id)
You probably already have the last one, because user.id is probably the primary key of the table.
Note that a left join approach is a bad idea in this case. The three tables -- posts, photos, and videos -- are independent of each other. If a user has five of each, then joining them together would produce 125 intermediate rows. If a user has fifty of each, it would be 125,000 -- a lot of extra processing.
Your answer is probably slow as it is using a correlated sub-query i.e. the sub query is running once for each user_id (unless the optimizer is doing something smart - which shouldn't be counted on).
You could use a left outer join and count or use something temporary like:
SELECT u.user_id,
u.user_name,
ph.user_count AS 'photoCount',
p.user_count AS 'postCount',
v.user_count AS 'videoCount'
FROM user u
INNER JOIN ( SELECT user_id,
COUNT(*) AS user_count
FROM photo
GROUP BY user_id
) ph
ON ph.user_id=u.user_id
INNER JOIN ( SELECT user_id,
COUNT(*) AS user_count
FROM post
GROUP BY user_id
) p
ON p.user_id=u.user_id
INNER JOIN ( SELECT user_id,
COUNT(*) AS user_count
FROM video
GROUP BY user_id
) v
ON v.user_id=u.user_id
There are pros and cons for both (depending on indexes). Always have a look at the query plan (using EXPLAIN for MySQL).
I have two table users and album. In users table there is user_id primary key .In other table albums there are multiple rows with that user_id because every time when a user upload a new album it uploads with user_id as foreign key. I want to select only once the user_id with other table(album) ignore other result set.
How can I achieve this?
SELECT a.*, b.*
FROM users a
INNER JOIN album b
ON a.user_ID = b.user_ID
INNER JOIN
(
SELECT user_ID, MAX(photo_id) max_rec
FROM album
GROUP BY user_ID
) c ON b.user_ID = c.user_ID AND
b.photo_id = c.max_rec
SELECT album.* FROM album LEFT JOIN users ON user.id = album.id WHERE user.id = SOMEIDHERE
I believe this will work, your not giving me a whole lot of info to work with.
SELECT *
FROM ( SELECT u.*, a.*
FROM users AS u
INNER JOIN album AS a
ON u.user_ID = a.user_ID
ORDER BY a.created DESC) AS h
GROUP BY user_ID
ORDER BY b.created DESC -> ORDER BY whatever row you wish for. In this case the newest one is chosen.
The following is what I got right now, which does not work properly because it checks one row for two different values.
SELECT users.*
FROM users INNER JOIN roles_users ru ON users.id = ru.user_id
WHERE ru.role_id = 1 AND ru.role_id = 2
I would like to select all users that have two rows in roles_users. The one rows role_id should have one and the second should have role_id two.
So select all users that have two rows in the roles_users where one of them has role_id = 1 and the other has role_id = 2.
The above query selects all users that have one row in roles_users that has first one and then two, that's why I get no results and it does not work. So how can I do this right?
SELECT users.id
FROM users INNER JOIN roles_users ON users.id = roles_users.user_id
WHERE roles_users.role_id IN (1, 2)
GROUP BY users.id
HAVING COUNT(*) = 2
Why not just join in on roles_users twice? Ala:
SELECT users.* FROM users
INNER JOIN roles_users ru1 ON users.id = ru1.role_id AND ru1.role_id = 1
INNER JOIN roles_users ru2 ON users.id = ru2.role_id AND ru2.role_id = 2
You need to get a (distinct) list of the users having the required roles. Try this instead:
SELECT users.{column_list}
FROM users as a
JOIN (SELECT user_id
FROM roles_users
WHERE role_id IN (1, 2)
GROUP BY user_id
HAVING COUNT(DISTINCT role_id) = 2) required_role
ON required_role.user_id = users.id