DISTINCT Is not working in inner join - mysql

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

Related

How to write a query that retrieves 3 replies for each user in my users table?

i want to display three replies from each user i have in my users table, so for instance if i have 3 users and each of them had replied to lets say 10 messages, i want my query to only retrieve 9 replies and not all of the replies in my messages_reply table.
heres what i tried:
$replyquery="select *
from messages_reply
LEFT JOIN users
ON messages_reply.from_id=users.id
GROUP BY messages_reply.id LIMIT 3";
i know that what i wrote means that bring me 3 replies only, so how do i bring 3 replies from each user in my users table?
In many databases, you can use row_number() for this:
select *
from (
select mr.*, u.*, row_number() over(partition by u.id order by mr.id desc) rn
from messages_reply mr
inner join users u on mr.from_id = u.id
) t
where rn <= 3
If you are running MySQL < 8.0, as I suspect from the lax use of group by in your query:
select mr.*, u.*
from messages_reply mr
inner join users u on mr.from_id = u.id
where mr.id >= (
select mr1.id
from messages_reply mr1
where mr1.from_id = u.id
order by mr1.id desc
limit 2, 1
)
This gives you the 3 message replies with the greatest id for each user.
Query not tested, just a concept
SELECT *
FROM users
LEFT JOIN (
SELECT *
FROM messages_reply
WHERE from_id = users.id
ORDER BY <your wanted order field> DESC
LIMIT 3) replies
ON users.id = replies.from_id

Display only top sum-up results using group by

My table records three different scores (site, park, division) for the same group of user.
A user's total score is "sum of all the site scores" + "sum of all the park scores" + "sum of all the division scores".
The code is the following and I am using MySQL:
select sum(points)as points, user_name
from
(SELECT sum(site_point) as points, user_name from visits v join users u on
u.user_id = v.user_id group by user_name
union
select sum(park_point) as points , user_name from visits v join users u on
u.user_id = v.user_id group by user_name
union
select sum(division_point) as points , user_name from visits v join users u
on u.user_id = v.user_id group by user_name
) V group by user_name order by sum(points) DESC ;
I want to display only the users whose score is in top 5 and their scores.
Ten users may have the same highest score. I need all of them being displayed.
I appreciate any help.
I think this is what you want:
select user_name,
sum(site_point + park_point + division_point) as points
from visits v join
users u
on u.user_id = v.user_id
group by user_name
order by points desc
limit 5;
A single aggregation simplifies the calculation.
You may not realize it, but the union is going to return incorrect results under some circumstances. Union removes duplicates, so if a user has the same partial scores, then the two rows becomes one.
EDIT:
It is a little trickier to get the top 5 scores, but possible:
select user_name,
sum(site_point + park_point + division_point) as points
from visits v join
users u
on u.user_id = v.user_id
group by user_name
having points >= (select distinct points
from (select sum(site_point + park_point + division_point)
from visits v join
users u
on u.user_id = v.user_id
group by user_name
) vu
order by points desc
limit 1 offset 4
)
order by points desc
limit 5;
Assuming that a user_name is unique for a given id you can simplify this a wee bit:
having points >= (select distinct points
from (select sum(site_point + park_point + division_point) as points
from visits v
group by user_id
) vu
order by points desc
limit 1 offset 4
)
And, if you want anyone who matches the top 5 users -- but to return more than 5 rows if there are ties -- then change the select distinct to select in the subquery.
Use the LIMIT command. More info here
So to tack it onto your SQL would result in:
select sum(points)as points, user_name
from
(SELECT sum(site_point) as points, user_name from visits v join users u on
u.user_id = v.user_id group by user_name
union
select sum(park_point) as points , user_name from visits v join users u on
u.user_id = v.user_id group by user_name
union
select sum(division_point) as points , user_name from visits v join users u
on u.user_id = v.user_id group by user_name
) V group by user_name order by sum(points) DESC LIMIT 5

Is it possible to connect to queries but get the results of first query before second one?

I want to select users from my db based on their interests and country and then i want to select them based on interests only.So here is my queries
SELECT users.*
FROM users
JOIN user_opt ON users.id = user_opt.UserId
WHERE user_opt.country IN(".implode(',',$Countries).") AND user_opt.Hobbies REGEXP '".implode('|',$Interests)."' LIMIT 100
SELECT users.*
FROM users
JOIN user_opt ON users.id = user_opt.UserId WHERE user_opt.country IN(".implode(',',$Countries).") LIMIT 100
Now i want to join them into one query,but get the results of first query before second one's.
Use union all and order by if you want to guarantee that the first results come before the second:
(SELECT u.* , 1 as which
FROM users u JOIN
user_opt uo
ON u.id = uo.UserId
WHERE u.country IN (".implode(',',$Countries).") AND
uo.Hobbies REGEXP '".implode('|',$Interests)."'
LIMIT 100
) UNION ALL
(SELECT u.*, 2 as which
FROM users u JOIN
user_opt uo
ON u.id = uo.UserId
WHERE uo.country IN(".implode(',',$Countries).")
LIMIT 100
)
ORDER BY which;
One probably solution can be
select * from
(select 1 AS sn, users.*
...
union
select 2 AS sn, users.*
...)
order by sn;

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;

Select rows in order of total count

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