Select rows in order of total count - mysql

I have a table of users which hold a a users id that they voted for like this:
uid | voted_for
1 | 3
2 | 3
3 | 1
What i'm aiming to do is order uid based on how many people have voted for that uid. But I have no idea how to do it.
So the end result would be:
uid | Total_Votes
3 | 2
1 | 1
2 | 0
Hope you can help explain the best way to structure the SQL for this.

Perhaps something like this will help joining the table on itself:
SELECT u.*, voted_for_cnt
FROM users u
LEFT JOIN (
SELECT voted_for, count(1) voted_for_cnt
FROM users
GROUP BY voted_for
) t ON u.uid = t.voted_for
ORDER BY t.voted_for_cnt DESC
SQL Fiddle Demo

This simple query will produce the output you requested:
select voted_for as uid, count(*) as total_votes
from users
group by 1
order by 2 desc
If you want all data about each user in the output, join users to itself:
select u.*, count(v.uid) as total_votes
from users u
left join users v on v.voted_for = u.uid
group by 1,2,3,4,5 -- put as many numbers here as there are columns in the users table
order by total_votes desc
This second query will give a total_votes score of zero if no one voted for the user.
Alternatively, you can select only those columns you want:
select u.uid, u.name, count(v.uid) as total_votes
from users u
left join users v on v.voted_for = u.uid
group by 1,2
order by 3 desc
```
To return only the winners, do this:
select u.uid, u.name, count(*) as total_votes
from users u
left join users v on v.voted_for = u.uid
group by 1,2
having count(*) = (
select max(c) from (
select count(*) as c from users group by voted_for))
order by 3 desc

Related

MySQL How to GROUP BY counted column?

I have two tables users, orders
each table has below column
users(table)
id
orders(table)
user_id
How can i get the number of users whose order count is 1,2,3,4 ....n?
Like this?
users count | order count
999 | 1
100 | 2
80 | 3
70 | 4
60 | 5
50 | 6
What I have been trying so far is
SELECT cnt.uid as u_cnt, cnt.ocnt as or_cnt
FROM (
SELECT u.id as uid, COUNT(o.id) as o_cnt
FROM users as u
INNER JOIN orders o on u.id = o.user_id
) as cnt;
GROUP BY or_cnt
BUT I get only 1 u_cnt and summed or_cnt
You need two levels of group by clauses here: First, you need to group by user and count the number of orders each user has. Then, you need to take that result, group by the number of orders and count how many users have such an order count.
The easiest way to achieve this is probably with a subquery, where both the inner and outer query have a group by clause:
SELECT cnt.ocnt as or_cnt, COUNT(*) as user_count
FROM (
SELECT u.id as uid, COUNT(o.id) as o_cnt
FROM users as u
INNER JOIN orders o on u.id = o.user_id
GROUP BY u.id -- This was missing in your original query
) as cnt
GROUP BY or_cnt
You can use two levels of aggregation. More importantly, you do not need a JOIN. All the information you need is in orders:
SELECT o_cnt, COUNT(*) as user_count
FROM (SELECT o.user_id, COUNT(*) as o_cnt
FROM orders o
GROUP BY o.user_id
) u
GROUP BY o_cnt
ORDER BY o_cnt;

Order data by data from another table

I have two tables:
rooms (all the rooms)
id | title | ...
-----------------
1 |Room 1 |
2 |Room 2 |
3 |Room 3 |
user_rooms (in which room is every user, column user is user's id and it's primary column)
user | room | ...
------------------
20 | 3 |
14 | 1 |
35 | 3 |
So I want to select all the rooms from the 'rooms' table but to order them in that way to show the rooms with the most users in them and after that the rooms with less and less users. For example, I want to show room 3 first (because 2 users are in it), then room 1 (one user in it), and finally room 2 (since no users are in it). How to achieve that?
SELECT aa.id, aa.title
FROM rooms AS aa
LEFT JOIN (
SELECT room, COUNT(*) AS total_count
FROM user_rooms
GROUP BY room
) AS _aa
ON aa.id = _aa.room
ORDER BY _aa.total_count;
This would often be done without a subquery:
select r.id, r.title, count(ur.room) as numusers
from rooms r left join
user_rooms ur
on r.id = ur.room
group by r.id, r.title
order by numusers desc;
This would often be more efficient than a version using a subquery in the from clause because it can take advantage of an index on the join key.
Interestingly, the same index would be used for a correlated subquery in the select, which is an alternative approach:
select r.id, r.title,
(select count(*)
from user_rooms ur
where r.id = ur.room
) as numusers
from rooms r
order by numusers desc;
This might be the most efficient approach, because it removes the aggregation in the outer query.
select r.id, r.title, coalesce(t.cnt,0)
from rooms r left join
(select room, count(*) as cnt
from user_rooms
group by room) t on t.room = r.id
order by t.cnt desc
This will give you only rooms with users
SELECT title, count(user) As MostUsers
FROM Rooms R
INNER JOIN user_rooms U
ON R.?field? = U.?field?
GROUP BY title
ORDER BY MostUsers
You need to complete the query inserting the names of the fields that you can use to Join the tables
If you want all rooms you can use a Left Join:
SELECT title, count(user) As MostUsers
FROM Rooms R
LEFT JOIN user_rooms U
ON R.?field? = U.?field?
GROUP BY title
ORDER BY MostUsers
Please try the following query:
select * from rooms r
order by (select count(1)
from userroom ur
where ur.roomid = r.roomid ) desc

MySQL select top rows with same condition values

I don't know how to title this problem. Correct me if you have better words.
I have two tables, Users and Posts.
Users:
id | username | password | ...
Posts:
id | author_id | title | content | ...
Now I want to list the "most active" users - the users who have written the most posts. And specifically, I want the top 10 result.
SELECT u.username, COUNT(p.id) AS count
FROM Posts p, Users u
WHERE u.id=p.author_id
GROUP BY p.author_id
ORDER BY count DESC
LIMIT 10;
I can get the expected result. However, the ranking may not be "fair" if some users have same number of posts.
E.g., I may get results like:
User 1 | 14
User 2 | 13
...
User 9 | 4
User 10 | 4
Here, there are actually several more users who have 4 posts.
So, the top 10 could be not exactly 10 results. How can I get a more "fair" result that contains extra rows of users who have 4 posts?
This is the right solution, I think: you need the subquery to know how much post has the 10th place in your top ten. Then, you use the outer query to extract the users with almost that postcount.
SELECT u.username, COUNT(p.id) AS count
FROM Posts p
JOIN Users u ON u.id = p.author_id
GROUP BY p.author_id
HAVING COUNT(p.id) >=
(
SELECT COUNT(p.id) AS count
FROM Posts p
JOIN Users u ON u.id = p.author_id
GROUP BY p.author_id
ORDER BY count DESC
LIMIT 9, 1
)
ORDER BY count DESC
Maybe not the best solution
select u.username, COUNT(p.id) AS count
FROM Posts p
join Users u on u.id = p.author_id
GROUP BY p.author_id
having COUNT(p.id) in
(
SELECT COUNT(p.id)
FROM Posts p
join Users u on u.id = p.author_id
GROUP BY p.author_id
ORDER BY count DESC
LIMIT 10
)
ORDER BY count DESC
Try this:
SELECT username, PostCount
FROM (SELECT username, PostCount, IF(#PostCount = #PostCount:=PostCount, #idx:=#idx+1, #Idx:=1) AS idx
FROM (SELECT u.username, COUNT(p.id) AS PostCount
FROM Posts p
INNER JOIN Users u ON u.id=p.author_id
GROUP BY p.author_id
) AS A, (SELECT #PostCount:=0, #Idx:=1) AS B
ORDER BY PostCount DESC
) AS A
WHERE idx <= 10;

DISTINCT Is not working in inner join

I have this query
SELECT DISTINCT u.fbid, u.name,r.points
FROM users u, players_records r
WHERE u.fbid = r.user_id
ORDER BY r.points DESC LIMIT 5
I want to get the top players but only different 5 players, this query is not working it shows duplicated users ids
any help ?
Result for the above query
1112222 Name 1 9310
3334444 Name 2 8380
3334444 Name 2 7010
5555666 Name 3 6080
1112222 Name 1 4890
so the ids are duplicated
It sounds like you want the maximum point per user. So you could do it something like this:
SELECT
users.fbid,
users.name,
maxRecords.points
FROM
users
JOIN
(
SELECT
MAX(players_records.points) AS points,
players_records.user_id
FROM
players_records
GROUP BY
players_records.user_id
) AS maxRecords
ON maxRecords.user_id=users.fbid
ORDER BY
maxRecords.points DESC
LIMIT 5
If I understand you data. Then the output will be like this:
1112222 Name 1 9310
3334444 Name 2 8380
5555666 Name 3 6080
If you need TOP 5 players by points:
SELECT TOP 5 u.fbid, u.name, max(r.points) AS points
FROM users u
LEFT JOIN players_records r ON u.fbid = r.user_id
GROUP BY u.fbid, u.name
ORDER BY points DESC
If you need TOP 5 players by SUM points:
SELECT TOP 5 u.fbid, u.name, SUM(r.points) AS points
FROM users u
LEFT JOIN players_records r ON u.fbid = r.user_id
GROUP BY u.fbid, u.name
ORDER BY points DESC
You could just select max score and group by user.
SELECT u.fbid, u.name, MAX(r.points) max_points
FROM users u, player_records r
WHERE u.fbid = r.user_id
GROUP BY u.fbid, u.name
ORDER BY max_points DESC LIMIT 5
Something like this might resemble what you want.
select fbid, u.name, sum(r.points) totalpoints
from users u join players_records r on u.fbid = r.user_id
group by fbid, u.name
order by totalpoints desc
limit 5

MySQL select query from two tables

I have two tables: users and works
I need write select query for count different names from users table where work_status = 1 from works table
The total is: 3 John, 1 Tom
I need get result:
John 2 (2 because one John work_status = 0 ant this not counting)
Tom 1
I have write select that can count different names, just need compared work_status..
SELECT name,COUNT(*) as num FROM users GROUP BY name
My query return:
There is a problem in your question. So here you have two solutions.
If there are three different John working on the company, this is your query
SELECT u.name, COUNT(*) as num
FROM users u INNER JOIN works w ON w.user_id = u.id
WHERE w.work_status = 1
GROUP BY u.name, u.id
If there are only one John working in the company, your query is this one:
SELECT u.name, COUNT(*) as num
FROM users u INNER JOIN works w ON w.user_id = u.id
WHERE w.work_status = 1
GROUP BY u.name
Note: If three John are the same person, you should delete the 2 last and on the works table change user_id = 3 and user_id = 4 for user_id = 1
This is a simple JOIN query:
SELECT u.name, COUNT(*) num
FROM users u
JOIN works w
ON w.user_id = u.id
AND w.work_status = 1
GROUP BY u.name
This one should do the job:
SELECT users.name,SUM(works.work_status) as num
FROM users,works
WHERE users.id=works.id
GROUP BY name
SELECT
users.`name`,
COUNT(*) num
FROM
users,
works
WHERE users.`id` = works.`user_id`
AND works.`work_status` = 1
GROUP BY users.`name` ;