MySQL ranking query - mysql

Query:
SELECT u.user_id,r.totalVotes votes,r.totalPoints rating,#row:=#row+1 rank
FROM mismatch_user u
LEFT JOIN ratingItems r ON u.user_id=r.uniqueName,
(SELECT #row:=0) pos
ORDER BY votes DESC,rating DESC
Output:
user_id votes rating rank
2 2 10 2
6 2 9 6
3 2 5 3
1 1 5 1
4 1 5 4
27 1 5 27
9 0 0 9
The ranking miserably not telling me the truth and it's basing on the user_id. Can anyone help me?

Does this help?
select r.*, #row:=#row+1 rank
from
(SELECT u.user_id,r.totalVotes votes,r.totalPoints rating
FROM mismatch_user u
LEFT JOIN ratingItems r ON u.user_id=r.uniqueName
) r
join (SELECT #row:=0) pos
ORDER BY r.votes DESC, r.rating DESC

You're generating a sequence and that can lead to tricky behavior.
If your query is correct, the safest way to sort by rank is now to embed it in another SELECT:
SELECT *
FROM (
SELECT u.user_id,r.totalVotes votes,r.totalPoints rating,#row:=#row+1 rank
FROM mismatch_user u
LEFT JOIN ratingItems r ON u.user_id=r.uniqueName,
(SELECT #row:=0) pos
ORDER BY votes DESC,rating DESC) T
ORDER BY rank;

Related

Select multiple tables with only unique users and ordered by latest id

I have 2 tables, first one is called members:
id name show
1 John 1
2 Wil 1
3 George 1
4 Chris 1
Second is called score:
id user_id score
1 1 90
2 1 70
3 2 55
4 3 30
5 3 40
6 3 100
7 4 30
user_id from score is the id of members.
What I want is to show a scorelist with unique members.id, ordered by score.score and order by the latest score.id.
I use the following code:
SELECT members.id, members.show, score.id, score.user_id, score.score FROM members
INNER JOIN score ON score.user_id = members.id
WHERE members.show = '1'
GROUP BY score.user_id
ORDER BY score.score DESC, score.id DESC
The output is not ordered by the latest score.id, but it does show only unique user_id's:
id user_id score
1 1 90
3 2 55
4 3 30
7 4 30
It should be like:
id user_id score
6 3 100
2 1 70
3 2 55
7 4 30
I hope you can help me
You could use:
with cte as (
select id,
user_id,
score,
row_number() over(partition by user_id order by id desc) as row_num
from score
) select cte.id,user_id,score
from cte
inner join members m on cte.user_id=m.id
where row_num=1
order by score desc;
Demo
If your MySQL server doesn't support windows function, use:
select s.id,s.user_id,s.score
from score s
inner join members m on s.user_id=m.id
where s.id in (select max(id) as id
from score
group by user_id
)
order by score desc;
Demo

PHP SQL order by multiple rows

I have a table called 'scorelist' with the following results:
ID USER_ID SCORE SEASON
-----------------------------
1 1 35 3
2 1 45 2
3 2 80 3
4 2 85 1
5 3 65 2
I want to make a score list where I show the scores of the users but only of their last played season.
Result should be:
ID USER_ID SCORE SEASON
-----------------------------
3 2 80 3
5 3 65 2
1 1 35 2
I use the following code:
SELECT * FROM scorelist
WHERE season = (
SELECT season FROM scorelist ORDER BY season DESC LIMIT 1
)
GROUP BY user_id
ORDER BY score DESC;
But then I only get the results of season 3, so a lot of users are not shown.
I also tried:
SELECT * FROM scorelist group by user_id ORDER BY score DESC, season DESC
But this is also not working.
I hope you can help me.
The subquery gets the latest season for each user. If you join to that you get your desired results
SELECT s1.*
FROM scorelist s1
JOIN
(
SELECT user_id, max(season) AS season
FROM scorelist
GROUP BY user_id
) s2 ON s1.user_id = s2.user_id AND s1.season = s2.season
Since MySQL 8.0 you can use window function row_number to solve this problem:
WITH ordered_scorelist AS (
SELECT
scorelist.*,
row_number() over (partition by USER_ID order by SEASON DESC) rn
FROM scorelist
) SELECT
USER_ID, SCORE, SEASON
FROM ordered_scorelist
WHERE rn = 1
ORDER BY SCORE DESC;
MySQL row_number test

MySQL: Find the average value per entry for the last x records

I'm trying to figure out how to grab the average rating for each salesperson over their last 100 ratings if they are currently employed, and if they have an average rating less than 3 (out of 5).
I have the following tables (leaving out information that isn't needed in the query):
users
id name employed
-----------------------
1 John 1
2 Sue 1
3 Bob 0
...
sales
id users_id
------------------
100 3
101 2
102 3
103 1
...
ratings
sales_id rating
-----------------
100 4
101 5
102 5
103 2
...
The current query I have searches everything and returns the average for all orders ever but I want it to only grab the most recent 100 ratings (or less if the salesperson hasn't sold that many items), still excluding anyone that is no longer employed or has a rating for their last 100 orders greater than 3. This is the current query:
SELECT u.name, avg(r.rating) as avg_rating, count(r.rating)
FROM users AS u
JOIN sales AS s ON s.users_id = u.id
JOIN ratings AS r ON r.sales_id = s.id
WHERE u.employed = 1
GROUP BY u.id
HAVING avg_rating <= 3;
Any help would be great! Thanks! :D
You can use my sql variables to keep track of the number of ratings so that you can get only recent 100 ratings , ordering by sales_id so you get recent ratings.
SQL FIDDLE DEMO
SELECT T.name, avg(T.rating) as avg_rating, count(T.rating)
FROM
(
SELECT u.name, r.rating, #num := if (#name = name, #num+1, 1) as rn,
#name:= name as var_name
FROM users AS u
JOIN sales AS s ON s.users_id = u.id
JOIN ratings AS r ON r.sales_id = s.id
AND u.employed = 1
JOIN ( select #name :='' , #num :=1) var
order by sales_id desc
)T
where T.rn <=100
GROUP BY T.name
HAVING avg_rating <= 3

How to get rank in MySQL from 2 tables?

I have 2 different tables in my database by the name of: rank, settings.
Here is how each table looks like with a few records in them:
Table #rank:
id points userid
-- ----- ------
1 500 1
2 300 2
3 900 3
4 1500 4
5 100 5
6 700 6
7 230 7
8 350 8
9 850 9
10 150 10
Table #settings:
userid active
------ ------
1 0
2 1
3 1
4 1
5 1
6 0
7 1
8 1
9 0
10 1
I want to get the rank of a specific user by user_id from the rank table ordering by their points. Also I would Only want to include the users in the ranking results, if they have active = 1 set in the settings table.
I have a simple ranking query, but it is not really effective, because it does include everyone even if the user is not active:
SELECT * FROM
(SELECT #sort:=#sort+1 AS sort, points, userid
FROM rank,
(SELECT #sort := 0) s
ORDER BY points DESC) t
WHERE userid= 8
Any idea, how could I achieve my goals here?
Few sub queries. First gets all the users who are active in the right order. That is used as a source for another query to add the rank. Then this is used as the source for the points and rank for the userid you are actually interested in
SELECT sort, points
FROM
(
SELECT #sort:=#sort + 1 AS sort, points, userid
FROM
(
SELECT rank.points, rank.userid
FROM rank
INNER JOIN settings
ON rank.userid = settings.userid
WHERE settings.active = 1
ORDER BY points DESC
) sub0
CROSS JOIN (SELECT #sort:=0) sub2
) sub1
WHERE sub1.userid = 8
Borrowing the idea from: https://stackoverflow.com/a/4474389/92063
SELECT
#rn:=#rn+1 AS RANK
,USER_ID
,POINTS
FROM (
SELECT
R.userid AS USER_ID
,R.points AS POINTS
FROM
rank R
INNER JOIN
settings S
ON R.userid = S.userid
WHERE
S.active = 1
ORDER BY
R.points DESC
) t1, (SELECT #rn:=0) t2;

Can i limit my result to a specific number in sql?

Select count(*) as c from casting where ord = 1 Group by actorid Order by count(*) DESC
The result is
15 15 14 13 12 10 7 7 7 7 5 5
Then i would like to get the result only greater than 10 ??how to do that thanks~~
SELECT count(*) AS c
FROM casting
WHERE ord = 1
GROUP BY actorid
HAVING c > 10
ORDER BY c DESC
You can consider HAVING the WHERE clause for GROUP BY aggregates.
SELECT COUNT(*) AS c FROM casting WHERE ord = 1 GROUP BY actorid HAVING COUNT(*) > 10 ORDER BY COUNT(*) DESC
HAVING c > 10
Place this between group by and order by