Hi all,
I was trying to rate the members according to the points they received & store it against their ID in the same table. For example:
User Points
A 10
B 30
C 20
D 50
E 40
(what code goes in here to make it like: )
User Points Rank
A 10 5
B 30 3
C 20 4
D 50 1
E 40 2
And update the database with those results?
Would appreciate it if anyone can guide me with this ! Thank you in advance.
Realistically you wouldn’t update the “Rank” in the database, you’d process it on the frontend w/ server-side code, one way (as there are others):
semi-pseudo code
// mysql connection crap
$query = mysql_query("SELECT * FROM table ORDER BY points DESC");
$i = 0;
while ( $row = mysql_fetch_array($query) )
{
$i++;
echo "rank: $i / user: $user / points: $points <br/>";
}
if you really wanted to store it in the db, each time the points are updated you’d just run an update script, that would reorder the rank information each time, using a similar counter method as above.
Thanks for your response, simplistik . I wanted to store that in the table. I was thinking of writing it in a script & run it as a cron every 5 hours or so. As I was waiting for the replies, I was thinking over it & I even thought, I
might get a situation where it might look like:
User Points Rank
A 10 4
B 30 2 ------- Same points ~ Same rank ???
C 20 3
D 50 1
E 30 2 ------- Same points ~ Same rank ???
As you can see, we have taken only 5 members & tried to allocate them the ranks which is including duplicate ranks. If there are at least 1000 members, realistically, at one time there might be 10 or even more members sharing the same number of points that means I would encounter duplicate ranking for all of them & I would need to stop that from happening. I think I would have to take any other factor apart from points, into consideration to be able to do this. So how do I then change it & store the ranks in the DB ? In fact, I am lost at the point where I can assign the rank to the member. How do I do that?
Please let me know. Thank you.
I really think you should not store this information in the database. From the component separation perspective, you would want to have the user and their points in the database since it is very static compared to ranking. You would then store their ranking in a more agile form, such as in the cache (memcache, file-system, etc.), so that it can be more quickly modified and used repeatedly by your application with minimal work.
If you insist on storing ranks in the database, you would want to add a column in the database with the rank. Then you fetch your entire list of users and sort them by their score. Then you iterate over the list of users (Sorted) and assign the rank, adding one to the rank as you go through unless the user before the current user has the same points.
$rank = 0;
for($i = 0; $i < count($sorted_users); $i++){
if($previous["points"] == $sorted_users*["points"]){
$sorted_users*["points"] = $rank;
}else{
$rank++;
$sorted_users*["points"] = $rank;
}
$previous = $sorted_users[$i];
}
Best luck!
Depending on the type of database you’re using, and your database experience, I think it might also be possible to define a function (or stored procedure? I don’t think that’s right) which you can select as an additional column just like the others. This might facilitate getting the ranking of a specific user without having to select all the users, but the underlying function would still need to analyze the relative value of points (and therefore still get a count of all users with more points).
Another solution entails listening for changes to a point value cell from within MySQL, and setting a trigger to increment/decrement a rank cell for all necessary rows. This is probably a much more efficient solution than the ones proposed above, because you only need to select the specific user to find a rank, rather than all users above (or below) him. In other words, it caches the value like you want, without the need to have your PHP script slow down waiting for the process to finish.
^ Like Jeff said, if you’re using PostgreSQL, you could likely use a stored procedure to speed things up exponentially. As far as I know, if you’re using MySQL, you’ll have to do some heavy lifting on the PHP side.
I don’t see why you can’t update the table from a trigger perspective - how often does the data in the table get modified?
If we are talking once every few minutes or a few times a minute (or less) then a trigger is fine, it’s transactional and can update the rank information factoring an insert, update or deletion.
I also propose that the user that got the score first gets the higher rank - two records wont share the same timestamp unless they were inserted in one transaction, so therefore inserting the timestamp and using this as part of the rank calculation would work.
Using a trigger means that the data would only get updated when the data changes (causing the most minimum of processing). The only issue with a trigger is that they can be slow if not optimised (read: badly written)
You can’t really calculate rank on the PHP server without selecting the entire user table to sort the data by (big no no), and doing it via a dynamic SQL statement or a static statement is slower than using a sproc/trigger as it is not pre-compiled and the execution plan must be calculated on the fly. (though repeated visits would make use of the cache)
Oh yes, MySQL does stored procedures by the way, in case anyone didn’t know 
I also disagree with this - seeing as rank is directly based on user points, rank is just as dynamic as user points and therefore needs to be updated each and every time user points are updated or users are added/removed.
Alternatively you don’t need to store rank, you can just select the data out based on the rank ordering (i.e. order by userpoints, dateadded) and you will automatically have the rank order - albeit with no pre defined row numbering (you can do that in PHP though)
Hi all,
I will try to follow your solutions & let you know how that works.
Thank you.