User ranking position in a table? - mysql

I have a game application, I'm keeping track of the number of games won per user, something like:
// table: users
id | username | num_games_won
How would I tell a user their overall ranking in terms of num_games_won? For example:
id | username | num_games_won
-----------------------------------
723 john 203
724 mary 1924
725 steve 391
The rankings would be: mary->0, steve->1, john->2. Given a username, how would I find their ranking number? (I'm using mysql)
Thanks

Try counting the number of users that have more games won that the user you are interested in (by id or username)
SELECT COUNT(*) FROM users
WHERE num_games_won > (SELECT num_games_won FROM users WHERE id = 723)

In this case you can do a simple ORDER BY. Unfortunately, MySQL doesn't support the nice analytical functions like RANK or ROWNUMBER that other databases support, because those would be other potential solutions when the answer isn't as simple as ORDER BY.
(edit: you can sort of cheat and simulate ROWNUMBER in MySQL thanks to this answer on SO)
In this case, you'd do SELECT * FROM users ORDER BY num_games_won DESC and the first row would have the most, the second would have second most, etc.

Related

getting count of players from mysql

I need to get the amount of users who have rank = player
So far I tried select count(*) as count_players from users where rank = player
I'm not sure where the error is, if only in the tags and query is correct or I'm going about it completely wrong, thanks in advance for the advice!
table: [users]
id
username
password
rank
1
john
$2y$10$zYharAUmf36hVzkYUg87y.avY
player
2
jane
$2y$10$zYhajIUGU89887jhgUg87yKJ8G
admin
COUNT_PLAYERS = 1
Cully below is right, it shouldn't need to be grouped when you're after a single result. You would do the following when you were after it grouped by rank (and you wouldn't do rank='player').
SELECT COUNT(*) AS count_players FROM users WHERE rank='player';
OR SELECT COUNT(*) AS count_players FROM users GROUP BY rank if you wanted it grouped.
Have you tried quoting the rank you're targeting? It's a string, not a variable.

MySQL: How to get TOP visited product for each user in a table?

I have a system with products. Everytime a user enters a product, I insert a record into my database.
I have a table with users and id_products, like this:
users id_product
____________________________
jondoe 2
george 9
jondoe 5
jondoe 2
george 9
george 9
george 2
I need a result (query) wich shows what is TOP visited product id for each user, so the result would be something like this:
jondoes most visited product is ID 2
georges most visitedproduct is ID 9
I was looking for the answer but I am not able to figure it out. Thanks a lot for your help, I appreciate it a lot.
Jan
This is a pain because it involves aggregation. One way to solve this uses a very complicated query. Another uses variables. A third method uses an aggregation trick that works under many circumstances:
select user,
substring_index(group_concat(id_product order by cnt desc), ',', 1) as mostCommonProduct
from (select user, id_product, count(*) as cnt
from t
group by user, id_product
) t
group by user;
One danger when using this method is that the intermediate result might be too long. You can set the group_concat_max_len system variable to get around that particular problem.

mysql: order by nearest id

i have a query that returns some users related to a specific user (Bob).
I need to retrieve the nearest records, meaning, i must return users whose ID column is near Bob's ID.
For example:
ID
Tom 5
Mike 8
Bob 10
Jack 12
Brian 13
The query:
SELECT users.* FROM users
INNER JOIN neighboors on neighboors.neighboor_id = users.id #ignore this join, just to exemplify
WHERE neighboors.user_id = 10 # bobs id
ORDER BY something
LIMIT 3 # i want to return only the 3 nearest users (according to the table above:mike, jack and brian)
How can i achieve this?
updated
the logic is, users can plant trees, each tree has an specie. The query should return users that have planted the same tree specie.
And why is important order by proximity of id? the client want this way :) there is no other reason.
Try with this, should do what you need :
SELECT users.* FROM users
INNER JOIN neighboors ON neighboors.neighboor_id = users.id
WHERE neighboors.user_id = 10
ORDER BY ABS(neighboors.user_id - 10)
LIMIT 3
The ABS function in this case it is used to calculate the "distance" from user_id selected value (the value filtered by the WHERE ... ).
To obtain better performance on large tables you have to index(if not yet) the column : neighboors.user_id .
One way to do this is to store the differences as a separate column in an inner query and then query for the smallest differences. A good example for nested queries is at :
http://dev.mysql.com/tech-resources/articles/subqueries_part_1.html
The problem is that nearness works in both a positive and negative direction.
If you had:
Tom 5
Mike 8
Sally 9
Bob 10
Sarah 11
Jack 12
Brian 13
Then do you want to return Mike, Sally and Sarah, or Sally, Sarah and Jack? Do you prefer ascending proximity or descending proximity?
It will help to know exactly what business logic this is trying to implement. Why is it important to select by proximity of the ID? How does the ID relate users to each other?
I'd be interested in helping if you can provide more details.

Selecting most recent as part of group by (or other solution ...)

I've got a table where the columns that matter look like this:
username
source
description
My goal is to get the 10 most recent records where a user/source combination is unique. From the following data:
1 katie facebook loved it!
2 katie facebook it could have been better.
3 tom twitter less then 140
4 katie twitter Wowzers!
The query should return records 2,3 and 4 (assume higher IDs are more recent - the actual table uses a timestamp column).
My current solution 'works' but requires 1 select to generate the 10 records, then 1 select to get the proper description per row (so 11 selects to generate 10 records) ... I have to imagine there's a better way to go. That solution is:
SELECT max(id) as MAX_ID, username, source, topic
FROM events
GROUP BY source, username
ORDER BY MAX_ID desc;
It returns the proper ids, but the wrong descriptions so I can then select the proper descriptions by the record ID.
Untested, but you should be able to handle this with a join:
SELECT
fullEvent.id,
fullEvent.username,
fullEvent.source,
fullEvent.topic
FROM
events fullEvent JOIN
(
SELECT max(id) as MAX_ID, username, source
FROM events
GROUP BY source, username
) maxEvent ON maxEvent.MAX_ID = fullEvent.id
ORDER BY fullEvent.id desc;

In MySQL, can I have a table returning the ten last rated games by rating?

The actual question is a little more complex than that, so here goes.
I have a website which reviews games. Ratings/reviews are posted for each game, and so I have a MySQL database to handle it all.
Thing is, I'd really like a page that showed what score (out of 10) meant what, and to illustrate it would have the game that was last reviewed as an example. I can always do it without, but this would be cooler.
So the query should return something like this (but running from 10 to 0):
|---------------*----------------*-----------------*-----------------|
* game.gameName | game.gameImage | review.ourScore | review.postedOn *
|---------------*----------------*-----------------*-----------------|
| Top Game | img | 10 | (unix timestamp)|
| NearlyTop Game| img | 9 | (unix timestamp)|
| Great Game | img | 8 | (unix timestamp)|
|---------------*----------------*-----------------*-----------------|
The information is in two tables, game and review. I think you'd use MAX() to find out the last timestamp and corresponding game information, but as far as complex queries go, I'm in way over my head.
Of course this could be done with 10 simple SELECTs but I'm sure there must be a way to do this in one query.
Thanks for any help.
Here is an ugly solution I found:
This query simply gets the IDs and scores of the reviews that you want to look at. I have included it so that you can understand what the trick is, without getting distracted by other stuff:
SELECT * FROM
(SELECT reviewID, ourScore FROM review ORDER BY postedOn DESC) as `r`
GROUP BY ourScore
ORDER BY ourScore DESC;
This exploits MySQL's 'GROUP BY' behavior. When the grouping is done, if the source rows have different values for different columns, then the value of the topmost source row is used. So if you had rows in this order:
reviewId Score
1 3
0 3
2 3
Then after you group by score, the reviewId is 1 because that row was on the top:
reviewId Score
1 3
So we want to put the most recent review on the top before we do the group by. Since ORDERing is always dones after grouping, in a single SELECT statement, I had to make a subquery to accomplish this. Now we just dress up this query a little bit to get all the fields you wanted:
SELECT `r`.*, game.gameName, game.gameImage FROM
(SELECT reviewID, ourScore, postedOn, gameID FROM review ORDER BY **postedOn DESC**) as `r`
JOIN game ON `r`.gameID = game.gameID
GROUP BY ourScore
ORDER BY ourScore DESC;
That should work.
SELECT DISTINCT game.gameName, game.gameImage, review.ourScore FROM game
LEFT JOIN review
ON game.ID = review.gameID
ORDER BY review.postedOn
LIMIT 10
Or something like that, check out how to use the Distinct first, I'm not sure on the syntax, and you may have to tell the ORDER BY DESC or ASC depending on what you want.
Well..
SELECT game.gameName, game.gameImage, review.ourScore
FROM game
LEFT JOIN review ON game.gameID = review.gameID
GROUP BY review.ourScore DESC
LIMIT 10
returns a list of games grouped by each individual score. But this isn't what I want, I want the game that is last posted - this is why the timestamp is important. With that query, MySQL returns the first result it can find.
I think this would work:
select g.gameName, g.gameImage, r.ourScore, r.postedOn
from game g, review r
where g.gameId = r.gameId
and r.postedOn = (select max(sr.postedOn)
from review sr where sr.ourScore = r.ourScore)
group by r.ourScore
order by r.ourScore desc;
Edit: above SQL was corrected after David Grayson's comment. I think this query is pretty easy to understand but probably performs poorly compared with his solution.