Getting position of a user in a mySql database - mysql

I'm trying to get the position of a specific user in a leaderboard for basketballScore. There is only one table in the database.
Here is the image of the database in mySQL
I imagine it would be something like this:
SELECT userID, SUM(points) as '`basketballScore`'
FROM user
ORDER BY SUM(points) DESC

You need a group by clause:
select userID,
SUM(score) as basketballScore
from user
group by userID
order by basketballScore desc
Also note that I reused the alias basketballScore in the order by clause.
If you need to create ranks, you can use user variables:
set #rank := 0;
select #rank := #rank + 1 as rank,
userID,
SUM(score) as basketballScore
from user
group by userID
order by basketballScore desc

You can get the rank of a specific user by doing:
select 1 + count(*) as rank
from user u
where u.basketballScore > (select u2.basketballScore from user u2 where u2.userId = #userId);

Related

Distinct values of an SQL Table

I have this table
and I want the 10 distinct rows with the highest score ordered descending.
So I tried
SELECT * FROM `highscores` GROUP BY userID ORDER BY score DESC LIMIT 10 ;
which is not correct because it returns:
Then I tried:
SELECT distinct(userID),userName,userLastname,score FROMhighscoresORDER BY score DESC ;
which is not correct too, because it doesn't really returns distinct rows based on userID.
And this is the result that I want:
I want to keep the highest score of each player(different userID) for the 10 first players. Any idea how can I do that?
SELECT a.*
FROM highscore a
INNER JOIN
(
SELECT userID, MAX(score) score
FROM highscore
GROUP BY userID
) b ON a.userID = b.userID
AND a.score = b.score
ORDER BY score DESC
LIMIT 10
this does not handle ties, though.
In MySQL you can use the DISTINCT operator with more than one column. The combination of all columns will be used to define the uniqueness of the row in the result set.
For example, to get the unique combination of city and state from the customers table, you use the following query:
SELECT DISTINCT state, city
FROM customers
WHERE state IS NOT NULL
ORDER BY state, city
Try this:
SELECT userID,userName,userLastname, MAX(score) as score
FROM highscores
WHERE userID in (
SELECT distinct userID FROM highscores )
ORDER BY score DESC
LIMIT 10;
Based on your question update:
SELECT h1.* FROM highscores h1
LEFT JOIN highscores h2 ON h1.userId = h2.userId and h1.score < h2.score
WHERE h2.score IS NULL
ORDER BY h1.score DESC
LIMIT 10
A different approach would be:
SELECT h1.* FROM highscores h1
JOIN (
SELECT userId, max(score) maxScore FROM highscores
GROUP BY userId
) h2 ON h1.userId = h2.userId and h1.score = h2.maxScore
ORDER BY h1.score DESC
LIMIT 10
The right query is:
SELECT userName, userLastname, userID, MAX( score )
FROM `highscores`
GROUP BY userID
ORDER BY MAX( score ) DESC
LIMIT 10
Thanks to EddieJamsession's comment.

SQL: select all the rows from the two userid's with great number of rows

I would like to get all the rows from the two users with the greatest number of rows, that is, the two users with the greatest activity in a log table.
I have only found next solution: first, get the number of rows for every user, an limit it to 2:
SELECT userid, count(*) AS n_of_rows FROM my_table GROUP BY userid LIMIT 2;
Then, from the source code I'm querying the database (Python for example), query the database to get the rows of each user:
SELECT * FROM my_table where userid = $userid
Is it the best/elegant solution, taking into account SQL language itself and database performance?
Thanks!
I think what you're looking for is something like
select * from my_table where userid in
(select userid from my_table
group by userid
order by count(*) desc
limit 2)
To get the rows and keep the order, use a join with aggregation:
select t.*
from my_table t join
(select userid, count(*) as cnt
from my_table
group by userid
order by count(*) desc
limit 2
) top2
on t.userid = top2.userid
order by top2.cnt desc, userid;
Try this:
SELECT TOP 2 userid, count(*) AS n_of_rows
FROM my_table
GROUP BY userid
ORDER BY count(*) desc

MySQL Calculate rank then update table from a result

My issue is I am trying to calculate all user entries and then rank them. After I rank them I want to update the users table to record each user's rank.
Tables:
userTbl
activityTbl
I have search all night and this is what I have so far.
SET #rank := 0;
SELECT * FROM (
SELECT #rank := #rank + 1 AS rank, a.userName
FROM activityTbl a
LEFT JOIN userTbl u ON a.userName = u.userName
GROUP BY a.userName
ORDER BY SUM( TIME_TO_SEC( a.actTime ) )DESC
) as sub
This returns:
rank|user
1 Kim
2 John
3 Joe
This is fine, but I've tried to add Update and Set to this query to update the userTbl and I just can't get it to work.
Please help! Let me know if you need more information.
UPDATE:
For those looking for exactly what I did to correct my problem.
First, I posted the wrong MySQL. The one I used to fix my problem is:
SET #rownum := 0;
SELECT #rownum := #rownum + 1 AS rank, userName, actTimeTotal
FROM (SELECT SUM(TIME_TO_SEC(actTime)) AS actTimeTotal , userName
FROM activityTbl
GROUP BY userName
ORDER BY actTimeTotal DESC) as result
Second, I created a rank table called rankTbl with 2 columns: rank smallInt and userName varchar.
Third, modified MySql script to:
SET #rownum := 0;
INSERT INTO rankTbl( rank, userName)
SELECT #rownum := #rownum + 1 AS rank, userName
FROM (SELECT SUM(TIME_TO_SEC(actTime))AS actTimeTotal , userName
FROM activityTbl
GROUP BY userName
ORDER BY actTimeTotal DESC) as result
ON DUPLICATE KEY UPDATE userName = VALUES(userName);
I changed the ON DUPLICATE KEY UPDATE to userName instead of rank. When rank changed the rank did not update for the userName. Using userName update changes in rank.
What you need to do is make sure that your ranking table has primary key on the user and then issue an INSERT of the SELECT with a KEY error provision:
Asuming your table is named tbl and contains a rank field and a user field, what I'm basically saying is that you need the following query to return a duplicate key error for all rows:
SET #rank := 0;
INSERT INTO tbl (rank, user)
SELECT #rank := #rank + 1 AS rank, a.userName
FROM activityTbl a
LEFT JOIN userTbl u ON a.userName = u.userName
GROUP BY a.userName
ORDER BY SUM(TIME_TO_SEC(a.actTime)) DESC;
Once you have that and you are sure it returns a duplicate key error for all rows it is trying to insert, you modify it as follows:
SET #rank := 0;
INSERT INTO tbl (rank, user)
SELECT #rank := #rank + 1 AS rank, a.userName
FROM activityTbl a
LEFT JOIN userTbl u ON a.userName = u.userName
GROUP BY a.userName
ORDER BY SUM(TIME_TO_SEC(a.actTime)) DESC
ON DUPLICATE KEY UPDATE rank = VALUES(rank);

How to give rank in query according to points

The below query is working absolutely fine, as I need. All the user get unique RANKS (User of same points should not get same rank)
SELECT
id,
first_name,
email,
(SELECT
rank
FROM ( SELECT
#rownum:=#rownum+1 rank,
u.id AS user_id,
points
FROM
user_master u, (SELECT #rownum:=0) r
ORDER BY
points
DESC) AS tmp
WHERE
user_id = um.id) AS Rank,
registered_date AS registered,
um.points as Points
FROM
user_master um
ORDER BY
um.id ASC
Now I want to make view for this query, it gives me error message
View's SELECT contains a subquery in the FROM clause
I've also tried first to make a view of user ranks to merge 2 different views. The below query gives perfect rankings of user but when I try to make view of this:
SELECT
#rownum:=#rownum+1 rank,
id AS user_id,
points
FROM
user_master u, (SELECT #rownum:=0) r
ORDER BY
points
DESC
..it gives me error message:
View's SELECT contains a variable or parameter
Is there any other way to apply rank in this query (Rank must be unique even if points are same).
Give this a go:
create view test_view as SELECT t.id,t.first_name,t.email,
(select sum(case when t1.points > t.points then 1
when t1.points = t.points and t1.id < t.id then 1
else 0 end) from user_master t1)+1 as rank, t.registered_date AS registered,
t.points as Points
from user_master t
order by points desc;

Automate MySQL fields (like Excel)

Say I have a table like ID, NAME, SCORE. Now normally, to get the rankings of the teams, I'd select all and order by. Sometimes though, I don't want to know all the rankings, just the ranking of one team. If I added a column RANK, is there any way for MySQL to automatically fill in those values for me based off of SCORE? (I believe MS Excel has this capability)
and if so, how does it handle ties?
thanks
You can calculate the rankings when you make your query:
SELECT * FROM (
SELECT teams.*, #rownum := #rownum + 1 AS rank
FROM teams, (SELECT #rownum := 0) T1
ORDER BY score DESC) T2
WHERE id = 1
It works by initializing a variable called rownum to 0 and then iterating over the rows in order of decreasing score. For each team the rownum is increased and the team is assigned a rank based on the current value of rownum. The outer select applies a where clause so that only one row is returned.
Here is an improved version that assigns the same rank to teams that have tied scores:
SELECT id, name, teams.score, rank FROM (
SELECT score, #rownum := #rownum + 1 AS rank
FROM (SELECT DISTINCT(score) FROM teams) T1, (SELECT #rownum := 0) T2
ORDER BY score DESC) T3
JOIN teams ON T3.score = teams.score
If this isn't fast enough for you, then use a trigger instead.
looks like I'm looking for a MySQL trigger
Get All Teams:
SELECT
s1.name,
s1.score,
COUNT(s2.name) + 1 AS rank
FROM scores s1
LEFT OUTER JOIN scores AS s2 ON (s1.score < s2.score)
GROUP BY s1.name
ORDER BY COUNT(s2.name)
Get One Team ('The Canucks'):
SELECT
s1.name,
s1.score,
COUNT(s2.name) + 1 AS rank
FROM scores s1
LEFT OUTER JOIN scores AS s2 ON (s1.score < s2.score)
GROUP BY s1.name
HAVING s1.name = 'The Canucks'
ORDER BY COUNT(s2.name)
The method shown in the above examples get the ranking dynamically (not filling a regular or temp table).
Note: both of these assume a given team only exists once in scores table for the rank value to be correct.