How to find total rows before required row [duplicate] - php

This question already has answers here:
Rank function in MySQL
(13 answers)
Closed 8 years ago.
I have a text based mafia game and I am selected some GameRecords. The game records are all defined in the "users" table. For this example I am using "totalcrimes". I need to select all the rows from the users table and order it by totalcrimes and then find out which row each specific user is that is viewing the page.
If I was the user that was "ranked" 30th it would echo "30". The code I use to find the top 5 is here however I need to expand on it:
<?php
$i = 0;
$FindCrimes = mysql_query("SELECT * FROM players WHERE status='Alive' AND robot = 0 ORDER BY `totalcrimes` DESC LIMIT 5");
while($Row = mysql_fetch_assoc($FindCrimes)){
$Username = $Row['playername'];
$TotalCrimes = number_format($Row['totalcrimes']);
$i++;
echo "
<tr>
<td bgcolor='#111111' width='5%'>$i</td>
<td bgcolor='#111111' width='50%'><a href='viewplayer?playerid=$Username'>$Username</a></td>
<td bgcolor='#333333' width='45%'>$TotalCrimes</a></td></td>
</tr>
";
}
?>

I am going to assume that you already have a variable set to hold the current users ID number and total crimes, so in this case I will use $user as my variable.
Change yours to fit.
Now, I see 2 instances in which you could mean as your post wasn't very specific, so I will address both.
To show the number at the top of the page, you would use something like;
<?php
$sql = "SELECT * FROM `players` WHERE `totalcrimes` > '{$user['totalcrimes']}'";
$run = mysql_query($sql);
$rank = mysql_num_rows($run) + 1;
echo 'Your rank: ' . $rank;
Other than that, I see it's possibly being used to highlight your row, so something like this would suffice;
<?php
$i = 0;
$FindCrimes = mysql_query("SELECT * FROM players WHERE status='Alive' AND robot = 0 ORDER BY `totalcrimes` DESC LIMIT 5");
while($Row = mysql_fetch_assoc($FindCrimes))
{
$Username = $Row['playername'];
$TotalCrimes = number_format($Row['totalcrimes']);
$i++;
$primary = '#111111';
$secondary = '#333333';
if ($Row['id'] == $user['id'])
{
$primary = '#222222';
$secondary = '#444444';
}
echo "<tr>
<td bgcolor='$primary' width='5%'>$i</td>
<td bgcolor='$primary' width='50%'><a href='viewplayer?playerid=$Username'>$Username</a></td>
<td bgcolor='$secondary' width='45%'>$TotalCrimes</a></td></td>
</tr>";
}
If neither of those give your requirements, please comment and I'll edit to suit.
edit: I've worked on games for a few years - care to share the link to yours?

This can do the trick
SELECT COUNT(*)+1 as rank
FROM users
WHERE totalcrimes > (SELECT totalcrimes
FROM users
WHERE user_id='12345' AND status='Alive' AND robot='0');
So it counts all rows with greater totalcrimes than selected user (in this example I have used user_id column and some id 12345), than adds 1 on that sum and returns as rank value.
Course, modify WHERE clause inside the brackets to make it work for you.
I assumed that table name is users and user's id is integer user_id.
Test preview (Navicat Premium):
What this query does? It returns number of selected rows + 1 as rank column, from the table users where totalcrimes is greater than totalcrimes of some user. That user's totalcrimes is selected by another query (by its user_id). If you have multiple users with same totalcrimes value, this query will return same rank for all of them.

Related

The sum of the user's points

I am a beginner when it comes to PHP and it is not my specialty, I am rather in the front end and I have a big problem.
I need to edit one of the tables after a guy who doesn't work with our company anymore and it seemed simple to me at first, but I can't find a solution.
I have a table with 4 columns: Date, Full Name, Login, and Points. Records of added points are saved in the database, but each action adding points creates a new record in the database, let's say:
Date
Full Name
Login
Points
04/10/2021
John Kovalsky
koval
10
04/11/2021
John Kovalsky
koval
20
04/12/2021
John Kovalsky
koval
15
The script below works, and I can almost understand the syntax, there is a display limit set here and a table pagination added. The script displays all records in the database.
The problem is that I need exactly the same, but with the sum of the user's points, so that a given user is displayed only once, and in the "Points" column, the sum of all his points is displayed.
I tried with the array_sum () function, but it enumerates all the records in the database for me. The script looks like this:
<?php
$login = $_GET['login'];
$_SESSION["login"] = $login;
include('Pagination.php');
include('config.php');
$limit = 200;
$queryNum = $db->query("SELECT COUNT(*) as ID FROM db_main");
$resultNum = $queryNum->fetch_assoc();
$rowCount = $resultNum['ID'];
$pagConfig = array(
'totalRows' => $rowCount,
'perPage' => $limit,
'link_func' => 'searchFilter'
);
$pagination = new Pagination($pagConfig);
$query = $db->query("SELECT * FROM db_main LIMIT $limit");
echo "<center>";
echo "<table id=\"tabela\" cellpadding=\"2\" border=1>";
echo "<tr>";
echo "<th>".'Date'."</th>";
echo "<th>".'Full Name'."</th>";
echo "<th>".'Login'."</th>";
echo "<th>".'Points'."</th>";
echo "</tr>";
echo "</tr>";
if($query->num_rows > 0){
?>
<?php
while($r = $query->fetch_assoc()){
echo "<tr>";
echo "<td>".$r['Date']."</td>";
echo "<td>".$r['Full_name']."</td>";
echo "<td>".$r['Login']."</td>";
echo "<td>".$r['Points']."</td>";
echo "</tr> </center>";
}
echo $pagination->createLinks();
}
?>
Please help, I have no idea how to do it. I will be very grateful for your help and hints.
You could do it by using a different query.
First, get all unique users.
$db->query("SELECT COUNT(DISTINCT(Full_name)) as ID FROM db_main");
Now get the collected data for each user.
$db->query("SELECT MAX(Date) AS Date, Full_name, Login, SUM(Points) AS Points FROM db_main GROUP BY Full_name LIMIT $limit");
Using the GROUP option will make sure you get one row per user.
The SUM will give you the amount of all the user's points.
The MAX(Day) will return user's the last day field.
There are two assumptions here, that the login is always the same for the user, and that the Points field is numeric and not a string.

How to randomly selected column from two tables in database PHP

i want to make reading toefl test. i have two tables named 'id_reading' and 'soal_reading'. id_reading table contain id and text. soal_reading contain id, question, option a b c d and answer. so i want to display data from that tables. but i want to display randomly all column in soal_reading tables except id column. i try but it wont random. please help.
<?php
include "conection.php";
$query = mysql_query("
SELECT id_reading.id
, text
, id_reading.text
, soal_reading.pertanyaan
, a
, b
, c
, d
, jawaban
from id_reading
, soal_reading
where id_reading.id = soal_reading.id
");
if ($query) {
while ($row = mysql_fetch_array($query)) {
echo "
<tr>
<td>".$row['id']."</td>
<td>".$row['text']."</td>";
$q = mysql_query("SELECT * from soal_reading order by rand()");
if ($q) {
while ($r = mysql_fetch_array($query)) {
echo "
<td>".$r['pertanyaan']."</td>
<td>".$r['a']."</td>
<td>".$r['b']."</td>
<td>".$r['c']."</td>
<td>".$r['d']."</td>
<td>".$r['jawaban']."</td>
<td>
Edit |
Delete
</td>
</tr>";
}
}
}
}
?>
Your query set in a random way questions but not fields in the question. So if you have 3 questions for example Q1, Q2,Q3 they are ordered in a random way, not the fields.
I suggest you to put your $r['a'] .... $r['d'] into an array and then extract a number from 0 to count($array) to get a possible answer and remove that element from the array. Do that until all possible answers are extracted. (count($array)==0).
In summary, your query provides you random order for your questions and in PHP you give a random order to your fields.
For some code, please comment.
Bye

Updating query to reflect normalized database

I am trying to make an article website, but I want to normalize my current database. I have four tables each labeling a category except for one. The four tables are: Entertainment, Lifestyle, Science, and Articles. Articles is the combination of all the entries of Entertainment, Lifestyle, and Science. I want to delete Entertainment, Lifestyle, and Science and just leave the Articles table, thus saving space and increasing performance. The only problem I am facing though is with a query that generates random articles by getting the last ID of the table, and then getting a random number between 6 and the max ID.
All my tables have the following structure: id (unique), category (the type of article this is, i.e Entertainment), title (title of the article), image (image URL of the article), link (URL of the article), Counter (number of views this article has), and dateStamp (the date the article was published). Here's the query I am trying to update based on my normalized database.
<?php
//SELECT the MAX id from the Entertainment table
$MAX_ID = $db->query("SELECT MAX(id) FROM Entertainment");
//Get Max id value
$MAX_ID = $MAX_ID->fetch_array();
$MAX_ID = $MAX_ID[0];
//Create random number variable
$RAND_NUM;
//If the Max ID is less than 6, make $MAX_ID the $RAND_NUM
if ($MAX_ID < 6) {
$RAND_NUM = $MAX_ID;
}
//Else get a random value between 6 and the Max ID
else {
$RAND_NUM = mt_rand(6, $MAX_ID);
}
//Grab 6 articles by descending from the random number, example: If $RAND_NUM is 7, get all entries from 7-2
$resultSet = $db->query("SELECT * FROM Entertainment WHERE id <= $RAND_NUM ORDER BY id DESC LIMIT 6");
if ($resultSet->num_rows != 0) {
//Booleans to check where we are at in the print off
$conditional = true;
$conditional2 = true;
echo "<div class='row'>";
while ($rows = $resultSet->fetch_assoc()) {
$image = $rows["image"];
$title = $rows["title"];
$link = $rows["link"];
$count = number_format($rows["Counter"]);
//Print off these articles on the left
if ($conditional == true && $conditional2 == true) {
echo "<div class='left'><a href='$link'><img src=$image><p>$title</p></a><p id='article-views'><span class='glyphicon glyphicon-fire'></span> $count Views</p></div>";
$conditional2 = false;
}
//Print off these articles on the right
else {
echo "<div class='right'><a href='$link'><img src=$image><p>$title</p></a><p id='article-views'><span class='glyphicon glyphicon-fire'></span> $count Views</p></div><hr>";
$conditional2 = true;
}
}
echo "</div>";
}
?>
How should I change/update this query to make it so that I get random Entertainment articles from the Articles table? I am open to any changes that improve the performance of the query as well.
Instead of selecting a random ending ID, just randomize all the rows and select 6 from them.
SELECT *
FROM Articles
WHERE category = 'Entertainment'
ORDER BY RAND()
LIMIT 6
If you need to avoid ORDER BY RAND() because it doesn't perform well enough, see How can i optimize MySQL's ORDER BY RAND() function?

High score system from my iphone game

I have this loop in PHP to select all my scores from my game from a MySQL table.
My query is:
$sql = "SELECT * FROM $table WHERE ";
switch($type) {
case "global":
$sql .= "1 ";
break;
case "device":
$sql .= "udid = '$udid' ";
break;
case "name":
$sql .= "name = '$name' ";
break;
}
$sql .= "ORDER BY $sort ";
$sql .= "LIMIT $offset,$count ";
$result = mysql_query($sql,$conn);
The udid is a unique identifier. And the loop:
while ($row = mysql_fetch_object($result)) {
echo '<tr>
<td>
'.$rank.'
</td>
<td>
'.$row->name.'
</td>
<td>
'.$row->score.'
</td>
<td>
'.$row->udid.'
</td>
</tr>';
$rank++;
}
My question is simple, so a person can see inside the game at which rank he is.
"How to select a rank from a udid, outside of the loop".
Perhaps making a new query which selects the rank from a udid, or set up a variable from in the loop?
Here's how to query the database for the rank for player udid 1:
SELECT COUNT(*) AS rank
FROM tablename
WHERE score > (SELECT score FROM tablename WHERE udid = 1)
I'm assuming a higher score is better and you're only storing the highest score for each player.
With an index on score and udid, this should be pretty speedy.
What the query does is count the number of users who have a greater score than the selected user.
If a lower score is better, simply change it to this:
SELECT COUNT(*) AS rank
FROM tablename
WHERE score < (SELECT score FROM tablename WHERE udid = 1)
Which counts the number of players with a lower score.
Read all about MySQL indexes.
One option is writing a function that calculate the user's rank based on all the other's scores and returning it.
Then , calling it when the user wants to see his rank.
As far as I know , MMORPG games (for instance) have a rank field in their DB for each
player and they use a daily or hourly cron-job to update that rank.
So instead of running the 'calculate-the-rank' function each and every time a player
just want to see his rank, you'll just need to fetch the value of the field.
EDIT: code for the function (don't forget to add the rank field to your DB table)
File:
cronjob_update_rank.php:
require 'config.php'; //Or whatever contains your config and DB connection.
$rank = 1; //The best player ranked as 1
$getMembers = mysql_query("SELECT id FROM members ORDER BY `score` DESC");
while($mem = mysql_fetch_array($getMembers))
{
mysql_query("UPDATE members SET rank='$rank' WHERE id='{$mem['id']}'");
$rank++;
}
Please notice , it's just a sample code , you'll need to customize it for your needs.
Use your server panel to create a daily cronjob on that file.
(or ask for your hosting provider support with it).

PHP MySQL select random rows

I have a problem selecting 6 random friends
This is the query I've got so far:
$result = num_rows("SELECT * FROM friends WHERE member_id = '".$_SESSION['userid']."'");
if($result >= 6) {
$f_num = 6;
} else {
$f_num = $result;
}
for($i = 1; $i <= $f_num; $i++) {
$q_get_member_friends = mysql_query("SELECT * FROM friends WHERE member_id = '".$_SESSION['userid']."' ORDER BY rand() LIMIT 1");
$r_get_member_friends = mysql_fetch_array($q_get_member_friends);
echo $r_get_member_friends['friend_with'];
}
I want to select 6 random friends if the logged in user has more or equal to 6 friends
Stuck on this for a while now :/
Thanks for any help :)
If you use:
SELECT *
FROM friends
WHERE member_id = '".$_SESSION['userid']."'
ORDER BY rand()
LIMIT 6
If the person only has 3 friends, the query will only show those three - it doesn't mean that the query will always return six rows.
The best way I've found to select any number of random records is with OFFSET in the query.
Let's say you want 6 random records, so I'll borrow from an answer above and count the total number of friends in the database.
$sql = mysql_query("SELECT COUNT(*) AS total FROM friends WHERE member_id='". $_SESSION['userid'] ."'");
$get_count = mysql_fetch_array($sql); // Fetch the results
$numfriends = $get_count['total']; // We've gotten the total number
Now we'll get the 6 random records out of the total above (hopefully it's > 6),
$query = mysql_query("SELECT * FROM friends WHERE member_id='". $_SESSION['userid'] ."' LIMIT 6 OFFSET " . (rand(0, $numFriends));
while ($rows = mysql_fetch_array($query))
{
/// show your $rows here
}
Using OFFSET may not be the best or most efficient, but it's worked for me on large databases without bogging them down.
Never mind, I figured it out :)
Had to use while not for :'D
First select the number of friends that the user has:
"SELECT COUNT(*) as numFriends FROM friends WHERE member_id='".$_SESSION['userid']."'
...put that into a variable, let's call it "$numFriends"
Then:
for($z=0;$z<6;$z++)
{
$randomFriendIndex = rand(1,$numFriends);
//Get the friend at that index
}
change limit 1 to limit 6 on the eighth line.
Instead of SELECT * at the beginning, try SELECT COUNT(*) and use the actual return value instead of num_rows().
Your loop could generate duplicates. I would suggest trying OMG Ponies answer.
There is a whole chapter about random selection in the book SQL Antipatterns.

Categories