To get the ranking of the user 3 I am using this query (It works fine):
$sql = "SELECT
score,
FIND_IN_SET(score,
(
SELECT GROUP_CONCAT(score
ORDER BY score DESC)
FROM results)
) AS rank
FROM results
WHERE user_id = 3
";
Table structure:
user_id - score
Now I want to give the user 3 some points. My formule is:
Number of score (Or users) - rank + 1.
So if I have 20 users (Or score) and the ranking of the user 3 is 10, so the points will be:
20 - 10 + 1 = 11 points.
PS: users (Or score) = some users have more than one score.
How can I get the number of score (Or users) using this mysql query?
SQL FIDDLE
http://sqlfiddle.com/#!9/ff4505/4
Check this ... I hope it help you ...
SELECT user_id,#all_user := (SELECT COUNT(*) FROM `results`) as all_count,((#all_user-score)+1) as rank FROM `results` WHERE user_id = 3
Improved Answer
$sql = "SELECT #all_user := (SELECT COUNT(*) FROM `results`)
as all_count,((#all_user-score)+1) as rank FROM `results` WHERE user_id = 3";
Related
My problem is,
I have a table in mysql
which colums are
id Student score
1 A 55
2 B 86
3 C 65
4 D 23
5 E 84
6 F 45
7 G 80
I want to find rank of any student in whole class based on score, with the student who scored just greater them him and an another student who scored just less them him.
for example if I am searching for student E
then output should be
id User score rank_in_classs
2 B 86 1
5 E 84 2
7 G 80 3
An another example can be that if I am looking for student A
id User score rank_in_classs
3 c 65 4
1 A 55 5
6 F 45 6
How can I find it using mysql query.
Thanks
Query
SELECT id, Student, score,
FIND_IN_SET( score, (
SELECT GROUP_CONCAT( score
ORDER BY score DESC )
FROM tbl )
) AS rank_in_class
FROM tbl
ORDER BY rank_in_class
LIMIT 3;
DEMO
Using the FIND_IN_SET() based solution proposed by Ullas you can locate a particular student +/- 1 rank this way:
set #this_rank := (
SELECT
FIND_IN_SET( score, (
SELECT GROUP_CONCAT( score
ORDER BY score DESC )
FROM tbl
)
) AS rank_in_class
FROM tbl
where student = 'A'
);
select
*
from (
SELECT
id
, Student
, score
, FIND_IN_SET( score, (
SELECT GROUP_CONCAT( score
ORDER BY score DESC )
FROM tbl
)
) AS rank_in_class
FROM tbl
) ric
where rank_in_class between #this_rank-1 AND #this_rank+1
ORDER BY rank_in_class
LIMIT 3;
Note: IF you stored the rank value in the table, then this would not be so cumbersome and could perform way better.
The best way to do that is probably with a mix of two queries and a little of PHP.
The first query retrieves the rank of the "focused" student you want;
The second query retrieves the range of all the students around the focused "student" with a dynamic LIMIT statement (this is where the use of PHP is unavoidable);
So something like this would probably do the job :
$user = 'C'; // Student user we want to "focus"
$range = 1; // Range around the "focus" : 1 before and 1 after (could be changed to anything else)
// First query : retrieving the rank of the "focused" student
$stmt = $mysqli->prepare('SELECT COUNT(*) AS Rank FROM Student AS Focused INNER JOIN Student as Others ON Others.Score > Focused.Score OR (Others.Score = Focused.Score AND Others.Id > Focused.Id) WHERE Focused.user = ?');
$stmt->bind_param('s',$user);
$stmt->execute();
$res = $stmt->get_result()->fetch_assoc();
$startRank = $res['Rank'];
// Computing the dynamic LIMIT
if (($startRank - $range) < 1) {
$offset = 0;
$rowCount = $startRank + $range + 1;
} else {
$offset = $startRank - $range;
$rowCount = ($range * 2)+1;
}
// Second query : retrieving the rank of all the students around the "focused" student
$stmt = $mysqli->prepare('SELECT id, user, score, #curRank := #curRank + 1 AS rank FROM Student, (SELECT #curRank := ?) Rank ORDER BY Score DESC, id DESC LIMIT ?, ?');
$stmt->bind_param('iii',$offset,$offset,$rowCount);
$stmt->execute();
This is probably the most optimized way to query the database to get what you want. As a bonus, you can change the range to whatever you like.
I have a table with some ratings for books;
These are some dummy records I have created to test this query out;
ID BookID RatersID Rating Date
1 2 3 5 (date)
2 2 4 4 (date)
SELECT `RatersID`,
COUNT(*) AS `raters`, `Rating`, COUNT(*) AS `Ratings`
FROM
`BOOKS_ratings`
GROUP BY
`BookID`
When I run the query I expected
BookID Raters Ratings
2 2 9
What I get:
RatersID raters Rating Ratings
3 2 5 2
I do not understand why this is happening?
/////////////////// Above has been answered
I have got the query working but when trying to receive the information in php the numbers are duplicated
E.g Raters = 2 PHP shows 22
Ratings = 9 PHP shows 99
$getratingq = mysqli_query($con,"SELECT `RatersID`, COUNT(*) AS `Raters`, sum(Rating) AS `Ratings` FROM `BOOKS_ratings` WHERE `BookID` ='$bookid' GROUP BY `BookID` LIMIT 1") or die("Get ratings query error");
if($getrating = mysqli_fetch_array($getratingq))
{
echo $ratings = $getrating['Ratings'];
$raters= $getrating['Raters'];
$rating = $ratings/$raters;
$stars = floor("$rating");
}
You need to use sum() to get the sum of Rating
SELECT
`BookID`,
COUNT(*) AS `raters`
sum(Rating) as Ratings
FROM
`BOOKS_ratings`
GROUP BY
`BookID`
Okay so I have a table that has the following
KEY username password score
The above columns are not in any specific order.
I want to send my Database a username and have it send me back what rank that user name is based on its score. So for example if I had 10 people in there and the 3rd person in has the highest score. When I pass the 3rd persons username in I want it to send back 1.
Is this possible?
I have been trying things like this
$result = mysql_query("SELECT * FROM tablename where username='$username' ORDER BY score DESC");
but it doesnt seem to give me the row number
This will handle ranks that have the same score.
SELECT d.*, c.ranks
FROM
(
SELECT Score, #rank:=#rank+1 Ranks
FROM
(
SELECT DISTINCT Score
FROM tableName a
ORDER BY score DESC
) t, (SELECT #rank:= 0) r
) c
INNER JOIN tableName d
ON c.score = d.score
// WHERE d.username = 'Helen'
SQLFiddle Demo (Ranking with duplicates)
SQLFiddle Demo (with filtering)
for example
KEY username password score Ranks
1 Anna 123 5 3
2 Bobby 345 6 2
3 Helen 678 6 2
4 Jon 567 2 4
5 Arthur ddd 8 1
for better performance, add an INDEX on column Score,
ALTER TABLE tableName ADD INDEX (Score)
SELECT
(SELECT COUNT(*)+1 FROM tablename WHERE score > t.score) as rank,
*
FROM
tablename t
where
username='$username'
The ORDER BY in your query is useless since you're only returning one row.
This is a more detailed question as my previous attempt wasn't clear enough. I'm new to MySQL and have no idea about the best way to do certain things. I'm building a voting application for images and am having trouble with some of the finer points of MySQL
My db
_votes
id
voter_id
image_id
_images
id
file_name
entrant_id
approved
_users
id
...
Basically I need to do the following:
tally up all votes that are approved
return the top 5 with the most votes
check if the user has voted on each of these 5 (return Boolean) from another table
I've tried variations of
SELECT i.id, i.file_name, i.total_votes
FROM _images i WHERE i.approved = 1
CASE WHEN (SELECT count(*) from _votes v WHERE v.image_id = i.id AND v.voter_id = ?) > 0 THEN '1' ELSE '0' END 'hasvoted'
ORDER BY i.total_votes DESC LIMIT ".($page*5).", 5
is that something I should try and do all in one query?
This query was working fine before I tried to add in the 'hasvoted' boolean:
SELECT id, file_name, total_votes FROM _images WHERE approved = 1 ORDER BY total_votes DESC LIMIT ".($page*5).", 5
At the moment I'm also storing the vote count in the _images table and I know this is wrong, but I have no idea about how to tally the votes by image_id and then order them.
Let me give this a shot to see if I understand your question:
SELECT i.*,(SELECT COUNT(*) FROM _votes WHERE i.id = image_id) AS total_votes, (SELECT count(*) from _votes where i.id = image_id and user_id = ?) as voted FROM _images AS i WHERE i.approved = 1
I have a table which stores high-scores, along with player ids. I want to be able to extract a record by a players id, and then get the rank, or position of their score in the table. Means, Basically I want to be able to say "you are in Nth" position, purely based on the players score against all other scores. For Example: if i am at 46th position then to me the position message will be like you are at 46th position out of total scores. Can anyone show me small example?
There are two ways of doing it:
Method 1:
SET #i = 0;
SELECT * FROM
scores s1 INNER JOIN (SELECT *, #i := #i + 1 AS rank FROM scores ORDER BY score DESC) AS s2 USING (id);
Method 2:
SELECT *, (SELECT COUNT(1) AS num FROM scores WHERE scores.score > s1.score) + 1 AS rank FROM scores AS s1
ORDER BY rank asc
This will provide duplicate rank values when there are duplicates:
SELECT t.playerid,
t.highscore,
(SELECT COUNT(*)
FROM TABLE x
WHERE x.playerid = t.playerid
AND x.highscore >= t.highscore) AS rank
FROM TABLE t
WHERE t.playerid = ?
IE: If three players have the same score for second place, they'll all have a rank value of two.
This will give a distinct value - three players tied for second place, only one will be ranked as 2nd:
SELECT x.playerid,
x.highscore,
x.rank
FROM (SELECT t.playerid,
t.highscore,
#rownum := #rownum + 1 AS rank
FROM TABLE t
JOIN (SELECT #rownum := 0) r
ORDER BY t.highscore DESC) x
WHERE x.playerid = ?
Here is an example.
You want to store the user's ID when they log in, like so...
$_SESSION['username'] = $usernamefromdb;
$_SESSION['id'] = $userid;
And then you want to open a session on every page on yoru website that you will be pulling dynamic information depending on the $_SESSION['id']
session_start();
Then find the row of data in the datebase according to the userID
$userid = $_SESSION['id'];
$rank_query = "SELECT * FROM table_name WHERE id='$userid'";
$rank_result = mysqli_query($cxn, $rank_query) or die("Couldn't execute query.");
$row = mysqli_fetch_assoc($rank_result)
Then using PHP, declare the nth postiion as a variable. And pull the total amount of rows from the DB
$rank = $row['rank'];
$all = $numrows = mysqli_num_rows($result);
echo out the players rank.
echo $rank . "out of" . $all;