I need to show user with the most comments. I have two tables:
Table: Users
ID | USERNAME | EMAIL
------------------------------
1 | USER01 | EMAIL01
2 | USER02 | EMAIL02
3 | USER03 | EMAIL03
4 | USER04 | EMAIL04
Table: Comments
ID | AUTHOR | COMMENT
----------------------------------
1 | USER01 | COMMENT...
2 | USER02 | COMMENT...
3 | USER01 | COMMENT...
4 | USER03 | COMMENT...
In this example the user01 have the most comments, but lets say I have to result them all with count of comments they have. And also in result I have to show users email which is stored in Users table.
How can I count and at same time check in both tables to return result? Or should I first get user info and then count ?
this query below handles duplicate rows having the most number of comments,
SELECT a.userName
FROM Users a
INNER JOIN Comments b
ON a.username = b.author
GROUP BY a.userName
HAVING COUNT(*) =
(
SELECT MAX(totalCount)
FROM
(
SELECT author, COUNT(*) totalCount
FROM comments
GROUP BY author
) a
)
SQLFiddle Demo
SQLFiddle Demo (with duplicate)
but if you want not to handle that, it can be simply done by using ORDER BY and LIMIT
SELECT a.userName, COUNT(*) totalCount
FROM Users a
INNER JOIN Comments b
ON a.username = b.author
GROUP BY a.userName
ORDER BY totalCount DESC
LIMIT 1
SQLFiddle Demo
select username,email,count(*) as cnt
from users, comments
where author = username
group by username
order by cnt desc
limit 1
Related
Similar to stackoverflow, I have a database of users who vote, comment, and make other actions. I am trying to return a sorted result of the top 10 users who have made the most actions based on the combined count of all of the actions a user has made, along with the actual count of total actions said user made.
Below is my table structure.
Users Table
Typical users data such as an incrementing id, username, email, etc.
| id | username |
-----------------
| 1 | bob |
| 2 | jane |
Votes Table
Has an incrementing id, user_id fk and type of vote made.
| id | user_id | type |
| 1 | 1 | up_vote |
| 2 | 2 | up_vote |
Comments Table
Same as the votes table, typical stuff here.
| id | user_id | comment |
---------------------------------
| 1 | 1 | hello, world |
| 1 | 1 | goodbye, world |
Intended results:
results needed
| total_actions | user_id | username |
-------------------------------------|
| 3 | 1 | bob |
| 1 | 2 | jane |
What I actually know how to do, albeit probably not the most efficient way...
Users sorted by most votes, along with the count
select `users`.*,
(
select count(*)
from `votes`
where `users`.`id` = `votes`.`user_id`
) as `votes_count`
from `users`
order by `votes_count` desc
limit 10
Users sorted by most comments, along with the count
select `users`.*,
(
select count(*)
from `comments`
where `users`.`id` = `comments`.`user_id`
) as `comments_count`
from `users`
order by `comments_count` desc
limit 10
Any help would be greatly appreciated!
You can left join aggregate queries that compute the total votes and comments per user, and sort in the outer query, like so:
select
coalesce(v.cnt, 0) + coalesce(c.cnt, 0) total_actions,
u.id,
u.username
from users u
left join (select user_id, count(*) cnt from votes group by user_id) v
on v.user_id = u.id
left join (select user_id, count(*) cnt from comments group by user_id) c
on c.user_id = u.id
order by total_actions desc
limit 10
While I prefer GMB's method (using LEFT JOIN with each subquery) I'll show here how to combine your existing queries. Just use both correlated subqueries, and add them together to get the total.
select `users`.*,
(
select count(*)
from `votes`
where `users`.`id` = `votes`.`user_id`
) +
(
select count(*)
from `comments`
where `users`.`id` = `comments`.`user_id`
) as total_actions
from `users`
order by total_actions desc
limit 10
I have two tables :
users:
___________________________
|user_id | username |
|_______________|___________|
| 1 | Dolly |
| 2 | Didi |
|_______________|___________|
forum:
_____________________________________________________________
|match_static_id| comment | timpstamp | user_id |
|_______________|___________|______________________|__________|
| 1 | Hi | 2013-07-10 12:15:03 | 2 |
| 1 | Hello | 2013-07-09 12:14:44 | 1 |
|_______________|___________|______________________|__________|
this query is working fine and it uses just thw forum table:
SELECT forum.match_static_id,
count(forum.match_static_id) 'comments_no', max(forum.timestamp)'timestamp'
FROM forum
GROUP BY forum.match_static_id
Order BY timestamp DESC
But the following query is using two tables :
SELECT forum.match_static_id,
count(forum.match_static_id) 'comments_no', max(forum.timestamp)'timestamp', users.username
FROM forum
INNER JOIN users on users.id = forum.user_id
GROUP BY forum.match_static_id
Here I want to get the user of the max(timestamp) but i get the wrong user could any body give my a clue about this, please?
Order BY timestamp DESC
Try this:
SELECT f1.match_static_id,
f2.comments_no,
f2.maxtimestamp,
users.username
FROM forum AS f1
INNER JOIN
(
SELECT match_static_id,
max(timestamp) maxtimestamp,
count(comment) AS comments_no
FROM Forum
GROUP BY match_static_id
) AS f2 ON f1.match_static_id = f2.match_static_id
AND f1.timestamp = f2.maxtimestamp
INNER JOIN users on users.user_id = f1.user_id;
See it in action here:
SQL Fiddle Demo
I'm trying to get the username and timestamp of the most recent post where topicID is, for example, 88.
Users
id | username
--------|----------
45234 | kaka
32663 | lenny
52366 | bob
Posts
id | message | topicID | timestamp | userID
--------|-----------|---------|-----------|-------
675 | hello | 88 | 100 | 32663
676 | hey | 88 | 200 | 45234
677 | howdy | 88 | 300 | 52366
So here I would want postID 677 and user bob.
Can I do this in a single sql query?
Would be great if I could implent it into this:
SELECT topics.id, topics.subject, topics.forum_id
FROM topics WHERE topics.forumID = 16
Assuming that table Topic is linked with table Post by Topic.ID = Post.TopicID and you want to get the latest post associated with it, you can have a subquery which basically gets the latest id (assuming it's set as auto-incremented column) for each topicID and join the result on table Post to get the other columns. Also you need to join on table User in order to get the name of the user who posted the entry.
SELECT a.id,
a.subject,
a.forumid,
b.message,
b.timestamp,
d.username
FROM topic a
INNER JOIN Posts b
ON a.id = b.topicID
INNER JOIN
(
SELECT topicID, MAX(id) id
FROM Posts
GROUP BY topicID
) c ON b.topicID = c.topicID AND
b.id = c.ID
INNER JOIN users d
ON b.userID = d.id
WHERE a.forumID = 16
if you remove the WHERE clause, you will get all the latest entry for each forumID.
SQLFiddle Demo
Untested, but off the top of my head, I think the following query will get you what you want:
SELECT Users.username, Posts.timestamp
FROM Users JOIN Posts on Users.id = Posts.userID
WHERE Posts.topicID = 88
ORDER BY Posts.timestamp DESC
LIMIT 1
I have 2 tables that look like this:
users (uid, name)
-------------------
| 1 | User 1 |
| 2 | User 2 |
| 3 | User 3 |
| 4 | User 4 |
| 5 | User 5 |
-------------------
highscores (user_id, time)
-------------------
| 3 | 12005 |
| 3 | 29505 |
| 3 | 17505 |
| 5 | 19505 |
-------------------
I want to query only for users that have a highscore and only the top highscore of each user. The result should look like:
------------------------
| User 3 | 29505 |
| User 5 | 19505 |
------------------------
My query looks like this:
SELECT user.name, highscores.time
FROM user
INNER JOIN highscores ON user.uid = highscores.user_id
ORDER BY time ASC
LIMIT 0 , 10
Actually this returns multiple highscores of the same user. I also tried to group them but it did not work since it did not return the best result but a random one (eg: for user id 3 it returned 17505 instead of 29505).
Many thanks!
You should use the aggregated function MAX() together with group by clause.
SELECT a.name, MAX(b.`time`) maxTime
FROM users a
INNER JOIN highscores b
on a.uid = b.user_id
GROUP BY a.name
SQLFiddle Demo
Your effort of grouping users was correct. You just needed to use MAX(time) aggregate function instead of selecting only time.
I think you wrote older query was like this:
SELECT name, time
FROM users
INNER JOIN highscores ON users.uid = highscores.user_id
GROUP BY name,time
But actual query should be:
SELECT user.name, MAX(`time`) AS topScore
FROM users
INNER JOIN highscores ON users.uid = highscores.user_id
GROUP BY user.name
I'm trying to formulate an SQL query for a messaging system that will return a list of all threads which have a status of 'OPEN' and whose last message was not posted by a user in a certain group.
The tables involved in the query are:
threads
-------
threadId
timestamp
subject
status
clientId
messages
--------
messageId
userId
messagebody
timestamp
threadId
users
-----
userId
username
groupId
The current query is:
SELECT threadId, timestamp, subject, status, clientId
FROM threads
WHERE status='OPEN'
ORDER BY timestamp DESC
which works fine; but I now have a new requirement - if the last message in the thread was posted by a user with a groupId of 1 then it should NOT be in the result set.
Including the information I need is simple enough:
SELECT threadId, timestamp, subject, status, clientId
FROM threads
INNER JOIN messages USING(threadId)
INNER JOIN users USING(userId)
WHERE status='OPEN'
GROUP BY threadId
ORDER BY timestamp DESC
but at this point I get stuck, because I can't figure out how to get the query to filter out threads based on the messages.userId with the highest timestamp within a particular group. I've looked at HAVING and all the aggregate functions and nothing seems to fit the bill.
Edit
I may not have been clear enough, so I'll try to illustrate with an example.
Here's some example data:
threads
threadId | timestamp | subject | status | clientId
--------------------------------------------------
1 | 1 | One | OPEN | 1
2 | 10 | Two | OPEN | 4
3 | 26 | Three | OPEN | 19
4 | 198 | Four | OPEN | 100
messages
messageId | userId | messagebody | timestamp | threadId
-------------------------------------------------------
1 | 3 | Hello, World| 1 | 1
2 | 1 | Hello | 3 | 1
3 | 1 | ^&%&6 | 10 | 2
4 | 2 | Test | 12 | 2
5 | 4 | Hi mum | 26 | 3
6 | 1 | More tests | 100 | 4
users
userId | username | groupId
---------------------------
1 | Gareth | 1
2 | JimBob | 2
3 | BillyBob | 2
4 | Bod | 3
In this example dataset threads 1 and 4 should be eliminated from the query because user Gareth (a member of group 1) is the last one to post to them (messageId 2 in threadId 1, and messageId 5 in threadId 4). So the result set should only have the thread data (threadId, timestamp, subject, status and clientId) for threads 2 and 3.
I've created an SQLfiddle for this test data.
Can anyone point me in the right direction here?
Sounds like you want this:
SELECT threadId, timestamp, subject, status, clientId
FROM threads t
INNER JOIN messages m
ON t.threadId = m.threadId
INNER JOIN users u
ON m.userId = u.userId
and u.groupId != 1 --placed the groupId filter here.
WHERE status='OPEN'
GROUP BY threadId
ORDER BY timestamp DESC
Edit, this appears to give you what you need:
SELECT t.threadId,
t.timestamp,
t.subject,
t.status,
t.clientId
FROM threads t
INNER JOIN messages m
ON t.threadId = m.threadId
INNER JOIN users u
ON m.userId = u.userId
WHERE status='OPEN'
AND NOT EXISTS (select t1.threadid
FROM threads t1
INNER JOIN messages m
ON t1.threadId = m.threadId
INNER JOIN users u
ON m.userId = u.userId
where u.groupid = 1
and t.threadid = t1.threadid)
ORDER BY timestamp DESC
see SQL Fiddle with Demo
Does adding LIMIT 1 to your query solve your problem?
SELECT threadId, timestamp, subject, status, clientId
FROM threads
INNER JOIN messages USING(threadId)
INNER JOIN users USING(userId)
WHERE status='OPEN'
GROUP BY threadId
ORDER BY timestamp DESC
LIMIT 1
Or changing the where clause to
WHERE status='OPEN' and groupID<>1
I think this is what you want?
select * from threads
where threadId not in
(
select messages.threadId
from messages
inner join (select threadId, MAX(timestamp) maxtime from messages group by threadId) t
on messages.threadId = t.threadId
and messages.timestamp = t.maxtime
where messages.userId=1
)