Calculate the Student Rank - php

I have followed the previous question and answer through this link:
Fetch the row of next in rank to the “rank of last id”?
Sadly, I couldn't get the result as I expected.
The expected result:
id score rank
1 78 4
2 80 3
3 100 1
4 88 2
5 56 5
In database, I have the id, score in my table: result.
Now, what I am trying is too put the rank in the table.
My code is as below:
<?php
include ('config.php');
?>
<!DOCTYPE html>
<html>
<head>
<title>ranking</title>
</head>
<body>
<?php
if($db){
//Create Query
$sql = "SELECT * FROM result ORDER BY score DESC";
//Execute Query
$result = mysqli_query($db,$sql);
if($result -> num_rows > 0){
//output data for each row
echo "
<br><br>
<table align='center'; border=1; style='text-align:center'>
<tr>
<td colspan='4'>RANKING TABLE</td>
</tr>
<tr>
<th>Bil</th>
<th>ID</th>
<th>Result</th>
<th>Rank</th>
</tr>
";
$i = 0;
//Store rows by rank + get the last_id_rank from the first row
$by_ranks = array();
$last_id_rank = FALSE;
//Display Result
while($row = $result -> fetch_assoc()){
$i++;
echo "
<tr>
<td>".$i."</td>
<td>".$row["id"]."</td>
<td>".$row["score"]."</td>
<td>".$row["rank"]."</td>
</tr>
";
$by_ranks[$row["rank"]][]=$row;
if($last_id_rank === FALSE){
$last_id_rank = $row["rank"];
}
}
//Get the result
$get_results = function($by_ranks, $last_id_rank){
//Get sorted array that's smaller $last_id_rank
$ranks = array_filter(array_keys($by_ranks),function($var) use ($last_id_rank){
return $var < $last_id_rank;
});
rsort($ranks); //Sort ranks by DESC
//Get rank that is just smaller than $last_id_rank
if(sizeof($ranks) == 0){
return array();
}
else{
return $by_ranks[$ranks [0]];
}
};
$results = $get_results($by_ranks,$last_id_rank);
//Display results
foreach($results as $row){
echo "
<br><br><br><br>
<tr>
<td>{$row["id"]}</td>
<td>{$row["score"]}</td>
<td>{$row["rank"]}</td>
</tr>
";
}
echo "
</table>
";
}
}
else{
echo "Failed to connect";
mysqli_close($db);
}
?>
</body>
</html>
The data in my database is as below:
id score rank
1 78 0
2 80 0
3 100 0
4 88 0
5 56 0

Given your table structure, you could update the table to have rank values with the following:
UPDATE result
LEFT JOIN result AS sub
ON sub.score > result.score
SET rank = COUNT(sub.id) + 1
The left join does the comparison with other rows in the table and setting the rank to the count with a higher score plus one gives you ranks starting at 1 instead of 0. Also, if you want ties to get the lowest rank that any of them would have, just change sub.score > result.score to use >=
Once you have your data in place, you can just access the rank values in php from the result of your SQL query and don't need to do calculations on the fly.

To create the result required from a table containing only id and score you could do the following.
select * from(
select id,score,(#rank:=#rank+1) as rank
from tbl
cross join
( select #rank:=0 ) T1
order by score desc
) T2
order by id
;
which results in
id score rank
1 78 4
2 80 3
3 100 1
4 88 2
5 56 5

Related

Taking mean of all students for one subject using php

I have an SQL table of students with one subject. I would like to take the mean of all the students for this particular subject such that:
Sum of the subject/Number of total students
The table looks like this:
Student ID : 1
=============
Maths : 40
Student ID : 2
=============
Maths : 60
Student ID : 3
=============
Maths : 90
Student ID : 4
=============
Maths : 0
So if the student has scored 0, then ignore this student and its score in calculating the mean.
<?php
if(!isset($_SESSION["loggedin"]) || $_SESSION["loggedin"] !== true){
header("location: login.php");
exit;
}
$db = new PDO("mysql:host=localhost; dbname=db;charset=utf8",'user','');
$sql = "SELECT * FROM Students";
$stmt = $db->query($sql);
while($data = $stmt->fetch(PDO::FETCH_OBJ)){
//How to take the mean of 1 subject for all students?
}
?>
Fix this line first so that...you can only get scores greater that 0
$sql = "SELECT * FROM students WHERE subjectscore > 0"; //assuming your column for scores is "subjectscore"
The the rest of the code to get mean should be
$stmt = $db->query($sql);
while($data = $stmt->fetch(PDO::FETCH_OBJ)){
$sumparts .= $data->subjectscore."+"; //Add a delimiter after every returned obj
}
print_r($sumparts); //For debug :to see which ones are selected
$sumarr = explode("+",$sumparts); // Convert the delimited string to array
$sum = array_sum($sumarr); //Get sum of values of array in this case the scores
$divisor = count($sumarr) - 1; //The minus 1 is necessary since well the delimited string will always have 1 extra key therefore making the count to count 1 more unnnecessary key
$total = $sum/$divisor; //Sum of all divided by the total number of objects
echo $total;

PHP MYSQL display all values from table a but only matching values from table b where table b is separate loop

I'm struggeling to get the corresponding values from table b using while loops. I have the following data in my database:
Table A
number - entity
3000 - ent1
3010 - ent1
4000 - ent1
Table B
number - entity
3000 - 10
3010 - 10
3010 - 20
4000 - 20
3000 - 30
4000 - 30
Now, I need the data to output the following table, where the first column is from table a and the next columns are populated from table b:
ent1 - 10 - 20 - 30
3000 - 3000 - null - 3000
3010 - 3010 - 3010 - null
4000 - null - 4000 - 4000
I have tried combining two WHILE loops, but with no success:
$query_entity = "SELECT number, entity FROM table_a ORDER BY number ASC";
$result_entity = mysqli_query($mysqli, $query_entity);
while ($entities = mysqli_fetch_array($result_entity)) {
$entitiesAccount = $entities['number'];
$query_entity_tabtwo = "SELECT number, entity
FROM table_b
WHERE number = $entitiesAccount";
$result_entity_tabtwo = mysqli_query($mysqli, $query_entity_tabtwo);
while ($entities_tabtwo = mysqli_fetch_array($result_entity_tabtwo)) {
echo $entitiesAccount . " - " . $entities_tabtwo['number'];
}
}
The result I'm getting is not the one I want stated above because the result does not separate the "entity" field in table b. How can I alter my script to get the desired result?
You simply need to echo things in a slighly different place
$sql = "SELECT number, entity
FROM table_a
ORDER BY number ASC";
$result = mysqli_query($mysqli, $sql);
while ($row = mysqli_fetch_array($result_entity)) {
$entitiesAccount = $row['number'];
$sql = "SELECT number, entity
FROM table_b
WHERE number = $entitiesAccount";
$result2 = mysqli_query($mysqli, $sql);
echo $entitiesAccount;
while ($row2 = mysqli_fetch_array($result2)) {
echo " - " . $row2['number'];
}
echo '<br>';
}
Cue: This is where JOINS join us in this endeavor. BA DUM TSSSS
You can use the ANSI syntax or the traditional where clause, they both work the same.
In your case, you could write something like..
SELECT ta.number, tb.entity
FROM tableA as ta
LEFT JOIN tableB as tb ON tb.number = ta.number
WHERE ta.entity = 'ent1'; // I suppose this is where you do the selection
Now you have all the rows from tableA and respectively related rows from tableB
and lets say that you have fetched all the result inside the array variable named.... umm.... $result.
Now, All you need is a little metaphorical sleight of hand in php as below...
<?php
$result = []; // This comes from the mysql
$output = [];
$columns_raw = [];
$entity_name = 'ent1'; // This comes from your selection logic the same that goes to sql.
foreach ($result as $row) {
$columns_raw[] = $row['entity'];
$output[$row['number']][$row['entity']][] = $row;
}
$columns = array_unique($columns_raw);
?>
let me write you a little html too.
<table>
<thead>
<th><?php echo $entity_name; ?></th>
<?php foreach ($columns as $column) { ?>
<th><?php echo $column; ?></th>
<?php } ?>
</thead>
<tbody>
<?php foreach ($output as $number => $row) { ?>
<tr><?php echo $number; ?></tr>
<tr><?php
foreach ($columns as $column) {
if (array_key_exists($column, $row)) {
echo $number;
} else {
echo 'null';
}
}
?></tr>
<?php } ?>
</tbody>
</table>
...and voila!
NOTE:- This is totally something which can be called a 'blind code' and I didn't run it. But this should be enough to point you in the right direction.
You can generate the data entirely in one query. This way you can simplify your PHP to one while loop:
SELECT a.number AS ent1,
GROUP_CONCAT(CASE WHEN b.entity = 10 THEN b.number END) AS `10`,
GROUP_CONCAT(CASE WHEN b.entity = 20 THEN b.number END) AS `20`,
GROUP_CONCAT(CASE WHEN b.entity = 30 THEN b.number END) AS `30`
FROM table_a a
JOIN table_b b ON b.number = a.number
GROUP BY ent1
Output:
ent1 10 20 30
3000 3000 (null) 3000
3010 3010 3010 (null)
4000 (null) 4000 4000
Demo

php mysqli query select

I have 3 different tables
table 1 keep general scores over the year
table 2 and 3 is event specific
only common field in all 3 is a member ID
I need to select 5 top score results for each member from table1 combine them with 1 specific result from table 2 and 3
I managed to get everything together in a temp table, but cnt get the output the way I need it
example what i have and need.
Original code
$prevQuery = "SELECT distinct member_id FROM scores";
$prevResult = $conn->query($prevQuery);
while($row = $prevResult->fetch_assoc()) {
$scores=("SELECT member_id,event_id,event_date,event_score FROM scores where member_id = ".$id." ORDER BY event_score DESC LIMIT 5");
Query:
select * from temp_table order by mem_id asc
PHP:
you can simple do your expected result in your application like this
<?php
$result = array(array('mem_id'=>1,'location'=>'A','date'=>'20/05/2017','score'=>100),array('mem_id'=>1,'location'=>'B','date'=>'21/05/2017','score'=>103),array('mem_id'=>1,'location'=>'C','date'=>'22/05/2017','score'=>106),array('mem_id'=>1,'location'=>'C','date'=>'23/05/2017','score'=>108),
array('mem_id'=>2,'location'=>'A','date'=>'20/05/2017','score'=>105),array('mem_id'=>2,'location'=>'B','date'=>'21/05/2017','score'=>109),array('mem_id'=>2,'location'=>'C','date'=>'22/05/2017','score'=>111),array('mem_id'=>2,'location'=>'C','date'=>'23/05/2017','score'=>110));
$new_result=array();
foreach($result as $key=>$row)
{
$new_result[$row['mem_id']][]=$row;
}
echo "<table border='1px'>";
echo "<thead><tr><th>S.No</th><th>date</th><th>score1</th><th>date</th><th>score2</th><th>date</th><th>score3</th><th>date</th><th>score4</th></tr>";
echo "<tbody>";
foreach($new_result as $key=>$row)
{
echo "<tr><td>".$key."</td>";
foreach($row as $key1=>$row1)
{
echo "<td>".$row1['date']."</td>";
echo "<td>".$row1['score']."</td>";
}
echo "</tr>";
}
echo "</tbody>";
echo "</table>";
?>
OUTPUT :
S.No date score1 date score2 date score3 date score4
1 20/05/2017 100 21/05/2017 103 22/05/2017 106 23/05/2017 108
2 20/05/2017 105 21/05/2017 109 22/05/2017 111 23/05/2017 110

sql result in php matrix according sorted by branches/product/size

I've been trying hard to figure out how to do matrix from the result of an sql query where the x is location, y is the size/description and the data filling are the quantities available in each location according to the size and color.
I have it done using pl/sql but not php. I want to transform the forms to a web layout in order to access it from anywhere.
the query is:
$q5="select artdesc DECRIPTON , ARTUPRB PRICE$ ,depcode LOCATION, ARDQTDIS
QUANTITY from fgart a, fgartdep b where a.soccode='01' and artfam =:fam and
artdiv=:div and artsec=:sec and artsubsec =:subsec and
(EXISTS
(select distinct artserial from fgart where soccode ='01' and artsec =:sec
and artsubsec =:subsec and artfoucode =:wartfoucode and artserial = a.artserial)
or EXISTS
(select distinct artfoucode from fgart where soccode ='01' and artsec =:sec and
artsubsec =:subsec and artfoucode = a.artfoucode and artserial =:wserial))
and
b.soccode ='01' and b.bracode ='01' and a.artcode = b.artcode
and depcode <> '99'
AND ARDQTDIS <> '0'
order by artdesc";
I have a small query prior of this one where I catch all the variables and pass them to the above sql.
I have managed to do a normal listing using the below code:
<?php
$r7=oci_parse($oconn,$q5);
$r8 = oci_execute($r7);
sleep(100);
if (oci_execute($r7)){
usleep(100);
print "<TABLE border \"1\" cellpadding=\"3%\">";
$first = 0;
while ($row = #oci_fetch_assoc($r7)){
if (!$first){
$first = 1;
echo ("<TR> <TH bgcolor=\"#FF9900\" > <font color=\"FFFFFF\">" );
echo( implode("</TH><TH bgcolor=\"#FF9900\">", array_keys($row)));
echo ("</TH> </TR> </font> \n");
}
echo ("<TR><TD bgcolor=\"#D0D0D0\" >");
echo (#implode("</TD> <TD bgcolor=\"#F0F0F0\">",str_replace ($Woutl, Wdesc,
array_values($row))));
echo ("</TD> </TR>\n");
}
echo ("</TABLE>");
?>
Please if anyone can direct me the right track in order to get result similar to the below:
location (x) : dt sk abc ss
Item desc /size (y):
blue 46 2 1 0 4
blue 48 1 1 1 0
blue 50 0 0 2 1
grey 44 5 1 1 1
grey 46 4 1 1 1
grey 50 3 2 2 0

Combine total count for entries in 2 SQL tables

I can't seem to find the right way to do this so I was hoping someone could give me some direction?
The SQL Database is structured like this (I've removed the irrelevant stuff):
Requests
R_ID R_FulfilledBy
1 Bob
2 Craig
3 Bob
SIMs
SM_ID SM_FulfilledBy
1 Bob
2 Craig
3 Bob
I'm hoping to end up with this output:
Fulfilled By Requests
Bob 4
Craig 2
Here's my PHP/HTML:
<div id="table">
<?php
//Connect to MySQL Database
$connection = mysql_connect($runnerdbServer, $runnerdbUser, $runnerdbPass);
mysql_select_db($runnerdbName, $connection) or die("MysQL Error");
$query = "SELECT R_FulfilledBy, COUNT(R_ID) FROM Requests GROUP BY R_FulfilledBy ORDER BY COUNT(R_ID) DESC";
$result = mysql_query($query) or die(mysql_error());
?>
<!-- Number of Runners (Counts total number of records in Requests table) -->
<table border='0' width='50%'>
<tr>
<th>Runners Fulfilled</th>
<tr><td><?php
$query = mysql_query("SELECT * FROM Requests");
$number=mysql_num_rows($query);
echo $number;
?>
</td></tr>
</table>
<!-- Fulfillment Stats -->
<table border='0' width='50%'>
<tr>
<th>Name</th>
<th>Runners Fulfilled</th>
</tr>
<?
// Print out result (I want this to calculate requests fulfilled by each user in 'Requests' and 'SIMs' table)
while($row = mysql_fetch_array($result)){
echo "<tr>";
echo "<td>". $row['R_FulfilledBy'] ."</td>";
echo "<td>". $row['COUNT(R_ID)'] ."</td>";
echo "</tr>";
}
?>
</table>
At present it's only calculating the records from the 'Requests' table :(
You could union all the two tables together in a subquery:
select FulfilledBy
, count(*)
from (
select R_FulfilledBy as FulfilledBy
from Requests
union all
select SM_FulfilledBy
from SIMs
) as SubQueryAlias
group by
FulfilledBy
Use union all instead of union because the second eliminates duplicates; which would give everyone a maximum count of 1.
I'd go with this:
SELECT R_FulfilledBy, COUNT(*) +
( SELECT COUNT(*) FROM SIMs WHERE R_FulfilledBy = SM_FulfilledBy )
FROM Requests GROUP BY R_FulfilledBy

Categories