I have a table called Leaderboard with 2 columns, PlayerName and PlayerRating. I want to be able to access a specific PlayerName, get their PlayerRating but ALSO their rank (ex: are they first, 2nd, 10th?). I did some reading around and I did find a way, but I can't seem to translate it into PHP and actually print the value. Please keep in mind that I'm not very experienced with MySQLi or PHP.
I'm currently getting my PlayerRating the following way:
$CurrentRating = $Connection->query("SELECT CurrentRating FROM Leaderboard WHERE PlayerName='$PlayerName'")->fetch_assoc()["CurrentRating"];
I can just echo $CurrentRating; and job's done. Now to find the PlayerRank I found several posts explaining how my query should also have
SET #rank=0; SELECT #rank:=#rank+1 As rank
So the beginning I suppose would be:
query("SET #rank=0; SELECT #rank:=#rank+1 As rank, CurrentRating FROM Leaderboard [...]
But I can't seem to get it working and get a rank to print properly. I tried echoing $CurrentRating["rank"] and a few variations of the following:
$CurrentRank = $Connection->query("SET #rank=0; SELECT #rank:=#rank+1 As rank, SELECT CurrentRating FROM Leaderboard WHERE PlayerName='$PlayerName'")->fetch_assoc()["rank"];
Can someone please help me write this correctly?
Thanks in advance!
Your queries should be something like these when you want ranking based on CurrentRating.
Query
SELECT
Leaderboard.PlayerName
, Leaderboard.PlayerRating
, (#rank := #rank + 1) AS rank
FROM
Leaderboard
CROSS JOIN(
SELECT
#rank := 0
)
AS
init_user_variable
ORDER BY
Leaderboard.CurrentRating DESC
When you want a ranking with where filter you should use this query inside a delivered table like this.
Query
SELECT
Leaderboard_ranked.PlayerName
, Leaderboard_ranked.PlayerRating
, Leaderboard_ranked.rank
FROM (
SELECT
Leaderboard.PlayerName
, Leaderboard.PlayerRating
, (#rank := #rank + 1) AS rank
FROM
Leaderboard
CROSS JOIN(
SELECT
#rank := 0
)
AS
init_user_variable
ORDER BY
Leaderboard.CurrentRating DESC
)
AS
Leaderboard_ranked
WHERE
Leaderboard_ranked.PlayerName = 'playername'
PHP MySQLi Syntax
$connection = mysqli_connect("host/ip", "user", "password", "database");
$result = mysqli_query($connection, [query]);
while($row = mysqli_fetch_array($result)) {
echo $row['PlayerName'] . " " . $row['PlayerRating'] . " " . $row['rank'] "<br />"
}
SELECT COUNT(*) FROM Leaderboard WHERE CurrentRating > ?
With users Current rating as a parameter should be more or less enough
Related
Im using a suggestion from Daniel Vassallo here to rank entries in my mysql table.
The suggestion doesn't deal with ties and thats the way I want it as a newer entry does not get a higher rank than an older entry with the same score on my scoreboard that way and it works for my needs.
My problem is that I want to be able to use this type of ranking to get the ranking for a single user. So from the output of this query I would like to define a name so that the script returns the rank, name and score of only that user.
I have tried a lot of different methods and as some of them deal with ties the results for a single user end up different from what is displayed in the results of the code below.
Your help would be greatly appreciated....going grey over this!
this is my current code:
it currently outputs:
rank name score
me 1111
me 1111
you 1110
<?php
include("common.php");
$link=dbConnect();
$limit = safe($_POST['limit']);
$query = "SELECT name, score, #curRank := #curRank + 1 AS rank
FROM $dbName . `scores`, (
SELECT #curRank := 0
) q
ORDER BY score DESC LIMIT $limit";
$result = mysql_query($query);
$my_err = mysql_error();
if($result === false || $my_err != '')
{
echo "";
}
$num_results = mysql_num_rows($result);
for($i = 0; $i < $num_results; $i++)
{
$row = mysql_fetch_array($result);
echo $row[rank] . " ". $row['name'] . " - " . $row['score'] . "\n";
}
?>
UPDATE
To clarify on ties; the original script will always increment regardless of ties this is how I want it to be because I don't want it so ties are ranked the same (no joint places) and it just so happens the script will favour the first person to achieve the score so that a new player can't knock him/her off the top spot with the same score, they have to beat it.
I know this is deprecated as I have seen in allot of similar posts but I'm just trying to get the skeleton built before I add the meat to the bones.
As kindly suggested by Spencer7593 I have tried the following code without much luck so far.
<?php
include("common.php");
$link=dbConnect();
$limit = safe($_POST['limit']);
$query = "SELECT name, score, #curRank := #curRank + 1 AS rank
FROM $dbName . `scores`, (
SELECT #curRank := 0
) q
ORDER BY score DESC LIMIT $limit";
$result = mysql_query($query);
$my_err = mysql_error();
if($result === false || $my_err != '')
{
echo "";
}
$num_results = mysql_num_rows($result);
while ($row = $result->fetch_assoc()) {
if ( $row['rank'] == 'you' )
{
// output this row because it's for the specified user
echo $row['name'];
}
else
{
continue;
}
}
?>
To get rankings for a single user extracted from the query results, you could run through the results in PHP, just like you are doing, but "skip" the output of rows that aren't for the specified user.
There's no need for a for ($i=0;i< loop. Use a "while fetch" loop. (I'm loathe to give you any example code using the deprecated mysql interface; new development should use either mysqli or PDO.)
while ($row = $result->fetch_assoc()) {
if ( $row['name'] == 'you' ) {
// output this row because it's for the specified user
echo $row['rank'];
} else {
// skip this row
}
}
You make some noise about handling "ties", but what's not clear what you actually want as output. If you want rows that have the same value for "score" have the same value for rank, just handle that in your query. If the score on the current row matches the score from the previous row, don't increment the rank. e.g.
SELECT #curRank := IF(s.score=#prev,#curRank,#curRank + 1) AS rank
, s.name
, #prev := s.score AS score
FROM $dbName . `scores` s
CROSS
JOIN (SELECT #curRank := 0, #prev := NULL) q
ORDER BY s.score DESC
LIMIT $limit
Including potentially unsafe values into the SQL text leads to SQL Injection vulnerabilities; we're going to assume that you've guaranteed the values of $dbName and $limit are safe.
If you want the query to filter out rows for a particular name, then wrap that query in parens and reference it as an inline view, e.g.
SELECT v.rank
, v.name
, v.score
FROM ( SELECT #curRank := IF(s.score=#prev,#curRank,#curRank + 1) AS rank
, s.name
, #prev := s.score AS score
FROM $dbName . `scores` s
CROSS
JOIN (SELECT #curRank := 0, #prev := NULL) q
ORDER BY s.score DESC
LIMIT $limit
) v
WHERE v.name = 'you'
ORDER BY v.rank ASC
I got a little problem, I've got a database, in that database are different names, id, and coins. I want to show people their rank, so your rank has to be 1 if you have the most coins, and 78172 as example when your number 78172 with coins.
I know I can do something like this:
SELECT `naam` , `coins`
FROM `gebruikers`
ORDER BY `coins` DESC
But how can I get the rank you are, in PHP :S ?
You can use a loop and a counter. The first row from MySql is going the first rank,I.e first in the list.
I presume you want something like:
1st - John Doe
2nd - Jane Doe
..
..
right?
See: http://www.if-not-true-then-false.com/2010/php-1st-2nd-3rd-4th-5th-6th-php-add-ordinal-number-suffix
Helped me a while ago.
You could use a new varariable
$i = "1";
pe care o poti folosi in structura ta foreach,while,for,repeat si o incrementezi mereu.
and you use it in structures like foreach,while,for,repeat and increment it
$i++;
this is the simplest way
No code samples above... so here it is in PHP
// Your SQL query above, with limits, in this case it starts from the 11th ranking (0 is the starting index) up to the 20th
$start = 10; // 0-based index
$page_size = 10;
$stmt = $pdo->query("SELECT `naam` , `coins` FROM `gebruikers` ORDER BY `coins` DESC LIMIT {$start}, {$page_size}");
$data = $stmt->fetchAll();
// In your template or whatever you use to output
foreach ($data as $rank => $row) {
// array index is 0-based, so add 1 and where you wanted to started to get rank
echo ($rank + 1 + $start) . ": {$row['naam']}<br />";
}
Note: I'm too lazy to put in a prepared statement, but please look it up and use prepared statements.
If you have a session table, you would pull the records from that, then use those values to get the coin values, and sort descending.
If we assume your Session table is sessions(session_id int not null auto_increment, user_id int not null, session_time,...) and we assume that only users who are logged in would have a session value, then your SQL would look something like this: (Note:I am assuming that you also have a user_id column on your gebruikers table)
SELECT g.*
FROM gebruikers as g, sessions as s WHERE s.user_id = g.user_id
ORDER BY g.coins DESC
You would then use a row iterator to loop through the results and display "1", "2", "3", etc. The short version of which would look like
//Connect to database using whatever method you like, I will assume mysql_connect()
$sql = "SELECT g.* FROM gebruikers as g, sessions as s WHERE s.user_id = g.user_id ORDER BY g.coins DESC";
$result = mysql_query($sql,$con); //Where $con is your mysql_connect() variable;
$i = 0;
while($row = mysql_fetch_assoc($result,$con)){
$row['rank'] = $i;
$i++;
//Whatever else you need to do;
}
EDIT
In messing around with a SQLFiddle found at http://sqlfiddle.com/#!2/8faa9/6
I came accross something that works there; I don't know if it will work when given in php, but I figured I would show it to you either way
SET #rank = 0; SELECT *,(#rank := #rank+1) as rank FROM something order by coins DESC
EDIT 2
This works in a php query from a file.
SELECT #rank:=#rank as rank,
g.*
FROM
(SELECT #rank:=0) as z,
gebruikers as g
ORDER BY coins DESC
If you want to get the rank of one specific user, you can do that in mysql directly by counting the number of users that have more coins that the user you want to rank:
SELECT COUNT(*)
FROM `gebruikers`
WHERE `coins` > (SELECT `coins` FROM `gebruikers` WHERE `naam` = :some_name)
(assuming a search by name)
Now the rank will be the count returned + 1.
Or you do SELECT COUNT(*) + 1 in mysql...
I have a leaderboard that i am making but am wanting to display the current user rank on the top of my page, i have been trying to make the following code to work
<?
if(! defined('BASEPATH') ){ exit('Unable to view file.'); }
$sql = $db->Query("SELECT uid, SUM(`total_clicks`) AS `clicks` FROM `user_clicks` GROUP BY uid ORDER BY `clicks` DESC");
$tops = $db->FetchArrayAll($sql);
$j = 0;
foreach($tops as $top){
$j++;
$user = $db->QueryFetchArray("SELECT id,login,email,country,coins FROM `users` WHERE `id`='".$top['uid']."'");
?>
<?=$user['login']?>
<?}?>
this returns all the usernames in a nice row i have tried the following
<?=$user['top']?>
<?=$user['j']?>
i understand its something to do with the foreach statement that needs to be changed but i also know i am missing something.
What i am trying to achieve is Rank : 31
You can generate the rank directly in your query. Then you don't need a loop to calculate the rank
SELECT uid,
SUM(`total_clicks`) AS `clicks`,
#rank := #rank + 1 as ranking
FROM `user_clicks`, (select #rank := 0) r
GROUP BY uid
ORDER BY `clicks` DESC
I having problems connecting the below query together so that It works more efficient.Can someone please tell me how I can connect these two queries so that it is only one?
$rs_duplicate = mysql_query("select count(*) as total
from advertisers_account
where user_email='$user_email' ") or die(mysql_error());
list($total) = mysql_fetch_row($rs_duplicate);
}
$rs_duplicate_pub = mysql_query("select count(*) as total
from publishers_account
where user_email='$user_email' ") or die(mysql_error());
list($totalpub) = mysql_fetch_row($rs_duplicate_pub);
if ($totalpub || $total > 0)
{
echo "Not Available ";
} else {
echo "Available";
}
Use a UNION:
SELECT 'advertisers' AS which, count(*) AS total
FROM advertisers_account
WHERE user_email = '$user_email'
UNION
SELECT 'publishers' AS which, count(*) AS total
FROM publishers_account
WHERE user_email = '$user_email'
This query will return two rows, you can use the which column to tell whether it's advertisers or publishers.
This is how you could do it. you need to use joins, but you should make sure to not let any variables in the query be directly from an outside user like from a form submit. That will open you up to SQL Injection. Use Prepared Statements instead.
select count(*) as total from publishers_account INNER JOIN advertisers_account ON advertisers_account.user_email = publishers_account.user_email WHERE user_email='$user_email'
in response to:
Can someone please tell me how I can connect these two queries so that it is only one?
Why not:
Select
(select count(*) as total from advertisers_account where user_email='$user_email') +
(select count(*) as total from publishers_account where user_email='$user_email') as sumofCount
SELECT count(advertisers_account.id)
FROM publishers_account
LEFT JOIN advertisers_account ON publisher_account.email = advertisers_account.email
WHERE publisher_account.email = '$user_email';
If the count is greater than zero, then the email exists in both tables at least once. If it exists only in the left table (publishers), then the counter would be zero. If it doesn't exist at all in the left table, then you'll get no rows at all, even if it does exist in the right table (advertisers)
I recently created a scoring system where the users are ordered by their points on descending basis. First I used to store ranks in a column of its own. I used to run this loop to update the rank:
$i = 1;
$numberOfRows = mysql_query('SELECT COUNT(`id`) FROM sector0_players');
$scoreboardquery = mysql_query("SELECT * FROM sector0_players ORDER BY points DESC");
while(($row = mysql_fetch_assoc($scoreboardquery)) || $i<=$numberOfRows){
$scoreid = $row['id'];
$mysql_qeury = mysql_query("UPDATE sector0_players SET scoreboard_rank = '$i' WHERE id = '$scoreid'");
$i++;
}
And it was really hard, not to mention slow to actually run this on a huge amount of users.
Instead, I tried to construct a query and ended up with this.
SET #rownum := 0;
SELECT scoreboard_rank, id, points
FROM (
SELECT #rownum := #rownum + 1 AS scoreboard_rank, id, points FROM sector0_players ORDER BY points DESC
)
as result WHERE id = '1';
But, this is just a select statement. Is there anyway I could get around it and change it so that it updates the table just as the loop does?
Please try using the following query :
set #rownum:=0;
update sector0_players set scoreboard_rank=#rownum:=#rownum+1 ORDER BY points DESC;
PHP code can be ,
mysql_query("set #rownum:=0;");
mysql_query("update sector0_players set scoreboard_rank=#rownum:=#rownum+1 ORDER BY points DESC;");
You can try using the RANK function .. I haven't actually executed the SQL, but it should work
UPDATE sector0_players
SET scoreboard_rank =
(
SELECT srank
FROM
(
SELECT id,points, RANK() OVER (ORDER BY points) AS srank
FROM sector0_players T
) D
WHERE D.id = sector0_players.id
AND D.points = sector0_players.points
)