php mysql calculate each percentage - php

how do i calculate percentage in mysql for each user?
$q = $db->query("SELECT * FROM report LEFT JOIN user ON user.user_id= report.id_user WHERE date='$today' GROUP BY id_user");
$q1 = $db->query("SELECT SUM(r_amount) AS total FROM report WHERE date='$today' AND id_user=id_user");
$r1 = $q1->fetch_assoc();
$totalCharge = $r1['totalCharge'];
$sixtyPercent = $totalCharge * 0.60;
$fortyPercent = $totalCharge * 0.40;
while($r = $q->fetch_array(MYSQLI_ASSOC)) :
echo '<tr>';
echo '<td>'.$r['user_name].'</td>';
echo '<td align="center">'.$fortyPercent.'</td>';
echo '<td align="center">'.$sixtyPercent.'</td>';
echo '<td align="center"><strong></strong></td>';
echo '</tr>';
endwhile;
current result:
name 60% cut 40% cut total
user 1 60 40 100
user 2 60 40 100
user 3 60 40 100
expecting result:
name 60% cut 40% cut total
user 1 60 40 100
user 2 24 16 40
user 3 48 32 80

You aren't getting the expected results because your $totalCharge variable will never change (nor will it ever match the proper user_id).
Most likely what you'll want to do is write a SQL statement which combines the two statements you currently have, then simply loop through the results of that statement and do all of the calculations within that loop.
The SQL statement might look something like:
SELECT SUM(r_amount) AS totalCharge, report.*, user.*
FROM report
JOIN total ON total.id_user = report.id_user
LEFT JOIN user ON user.user_id= report.id_user
WHERE date='$today' GROUP BY user_id
You'll likely have to tweak it a little to get the expected results.
Then your loop will look something like:
while($r = $q->fetch_array(MYSQLI_ASSOC)) {
$totalCharge = $r['totalCharge'];
$sixtyPercent = $totalCharge * 0.60;
$fortyPercent = $totalCharge * 0.40;
echo '<tr>';
echo '<td>'.$r['user_name'].'</td>'; // corrected syntax error here
echo '<td align="center">'.$sixtyPercent.'</td>';
echo '<td align="center">'.$fortyPercent.'</td>';
echo '<td align="center"><strong></strong></td>';
echo '</tr>';
}
Hope this guides you to the solution.

Related

Update percentage column in database table based on count column of all qualifying rows

I want to update the percentage column based on the count data for all is_enabled = 1 rows in a table.
My coding attempt looks like this:
<?php
$total = '';
$result= mysqli_query($conn, "SELECT SUM(count) FROM My_Databse WHERE is_enabled ='1'");
while($row = mysqli_fetch_array($result)){
$total = $row['SUM(count)'];
}
$percentage = '';
$result= mysqli_query($conn, "SELECT * FROM My_Database WHERE is_enabled ='1' ORDER BY count DESC");
while($row = mysqli_fetch_array($result)){
$percentage = ($row[2] / $total) * 100;
echo '<div class="progress">';
echo '<div class="progress-bar" role="progressbar" aria-valuenow="'.$percentage.'" aria-valuemin="0" aria-valuemax="100" style="width:'.$percentage.'%">';
echo $row[1].'('.round($percentage).')';
echo '</div>';
echo '</div>';
$i++;
}
$result = mysqli_query($conn, "UPDATE My_Database SET percentage = ".$percentage." WHERE id = 1");
?>
I have now the problem, that I always get the last percentage. How can I update the percentage for every row?
Update query must be within while loop, after calculating percentage -
mysqli_query($conn, "UPDATE My_Database SET percentage = ".$percentage." WHERE id = ". $row['id'] );
I do not recommend making multiple trips to your database, nor using php for a task that can be simply, efficiently, directly, and completely done with a single query.
Join a derived table containing the count total for all qualifying rows, then build the arithmetic to calculate the percentage and update the rows accordingly.
It is more efficient to join the derived table versus calling the subquery for each qualifying row.
Code: (DB-Fiddle)
UPDATE my_table
JOIN (SELECT SUM(`count`) total FROM my_table WHERE is_enabled = 1) all_enabled
SET percentage = ROUND(`count` / total * 100)
WHERE is_enabled = 1;
New table data:
id
tutorial
count
is_enabled
percentage
1
House
3
1
6
2
Car
34
1
68
3
Tuna Fish
22
0
0
4
Bike
13
1
26
Depending on your circumstances (how often this table is read and written to), you might rather declare a TRIGGER to auto calculate&update the percentage column whenever count or is_enabled values are changed or a new row with is_enabled is INSERTed.

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/MySQL: how to dynamically change my (large and always changing) database

Scenario
I have a MySQL database with 10.000 rows. Setup of the database:
ID UniqueKey Name Url Score ItemValue
1 5Zvr3 Google google.com 13 X
2 46cfG Radio radio.com -20 X
3 2fg64 Yahoo yahoo.com 5 X
.... etc etc etc
As you can see, each item has a score. The score is constantly changing. Google may have a score of 13 now, but tomorrow it may be 80, or -50.
What I want:
I want to create a system that creates a hierarchy in my current database, based on the score of the items. Right now I'm thinking about percentile ranks, meaning that the highest scoring items will be close to 100%, and the lowest scoring items will be close to 0%. For this I created some code that will try to achieve what is shown here: http://www.psychstat.missouristate.edu/introbook/sbk14m.htm
This is my code:
$sql = "SELECT * FROM database order by Score";
$result = $conn->query($sql);
$count = 0;
while ($row = $result->fetch_assoc()) {
$woow = $row['Score'];
$sql = "SELECT * FROM database WHERE Score = $woow";
$resultnew = $conn->query($sql);
$somanythesame = $resultnew->num_rows;
$itemPercentile = ( ($count/$result->num_rows + 0.5*$somanythesame/$result->num_rows) * 100 );
$rowID = $row['ID'];
$sql2 = "UPDATE database SET itemValue = $itemPercentile WHERE ID = $rowID";
$conn->query($sql2);
$count++;
}
This works, but for one problem it does not: There are many items in my database, many with the same score. To illustrate my problem, here is a very simple 10-row database with only the Scores:
Scores
-10
0
0
0
10
20
20
30
40
50
The problem with my code is that it doesn't give the same percentile for the items with the same Score, because it takes in account all previous rows for the calculation, including the ones with the same Score.
So, for the 2nd, 3rd and 4th item with a Score of 0, it should be like this: (1/10 + 0.5*1/10) * 100. Problem is, that for the 3rd item it will do (2/10 + 0.5*1/10) * 100 and the 4th item it will do (3/10 + 0.5*1/10) * 100.
Then, for the 5th item with a score of 10, it should do (4/10 + 0.5*1/10) * 100. This is going well; only not for the items with te same score.
I'm not sure if I explained this well, I find it hard to put my problem in the right words. If you have any questions, let me know! Thank you for your time :)
You need to maintain an "identical count" ($icount) variable that tracks the number of items with an identical score and a "current score" ($score) that tracks the current score.
$icount = 0;
$score = null;
Increment $icount instead of $count when $woow == $score (identical value check). Otherwise, add it to your $count and increment, and then reset the $icount value to 0.
if ($woow == $score) {
$icount++;
} else {
$count += $icount + 1;
$icount = 0;
}
Finally, set your $score value to the latest $woow for testing in the next iteration of the loop:
$score = $woow;
This will allow items with the same Score to have the same $count value, while incrementing an additional $icount times when a new $score is found.
Your final code will look like this:
$sql = "SELECT * FROM database order by Score";
$result = $conn->query($sql);
$count = 0;
$icount = 0;
$score = null;
while ($row = $result->fetch_assoc()) {
$woow = $row['Score'];
$sql = "SELECT * FROM database WHERE Score = $woow";
$resultnew = $conn->query($sql);
$somanythesame = $resultnew->num_rows;
$itemPercentile = ( ($count/$result->num_rows + 0.5*$somanythesame/$result->num_rows) * 100 );
$rowID = $row['ID'];
$sql2 = "UPDATE database SET itemValue = $itemPercentile WHERE ID = $rowID";
$conn->query($sql2);
if ($woow == $score) {
$icount++;
} else {
$count += $icount + 1;
$icount = 0;
}
$score = $woow;
}
You can change $sql query:
$sql = "SELECT *,count(*) FROM database group by Score order by Score";
In this case, you fetch score with counts and no more select needed in the while loop.
Even you can select Percentile in MySQL query:
Select t2.* , #fb as N , ((t2.fb1 + 0.5 * t2.fw)/#fb*100) as percentile from (
Select t1.* , (#fb := #fb + t1.fw) as fb1 from (
Select score,count(*) as fw From tablename group by score order by score ASC
) as t1
) as t2
I think this query returns most of columns which you may needs to check results.

Displaying only 1 column in last row

I've checked the queries in phpMyAdmin a lot of times and is dead sure they are absolutely correct. Also, if I manually write the loop 3 times, setting 2,3,4 instead of incrementing counter it still displays ONLY one column in last row. First two rows result is accurate.
foreach($row as $rec) is basically running 17 times from another query which is printing table headers.
$by_type1 = array("First","Second+","Final");
$counter = 2; //this counter represents type of interview (2-First, 3-Second+, 4-Final)
foreach ($by_type1 as $type1)
{
$table_row = '<tr><td class="rborder">'.$type1.'</td>';
foreach ($row as $rec)
{
$id=$rec['id'];
$qry2 = "SELECT
CONCAT( r.fname, ' ', r.lname ) AS rname,
ch.status_id as Type,
count(ch.status_id) as number
FROM candidateJoborderHistory ch
LEFT JOIN candidates_info c ON ch.candidate_id = c.candidate_id
LEFT JOIN recruiters r ON c.recruiter_id=r.recruiter_id
LEFT JOIN interviewtypes i ON ch.interview_id = i.interview_id
WHERE c.recruiter_id = $id AND UNIX_TIMESTAMP(ch.date_interview) BETWEEN 1401667200 AND
1402099200 AND ch.status_id = $counter
group by ch.status_id";
global $conn;
$conn->open();
$stmt2 = $conn->prepare($qry2);
$stmt2->execute();
$row2 = $stmt2->fetchAll();
foreach($row2 as $row_x)
{
$table_row .= '<td>'.$row_x['number'].'</td>';
}
}
$table_row .='</tr>';
echo $table_row . "\n";
$counter++;
}
What I want is:
First 6 6 4 4 11 6 12 3
Second+ 3 1 2 1 3
Final 3 2 1 4 1
But what I am getting is:
First 6 6 4 4 11 6 12 3
Second+ 3 1 2 1 3
Final 3
Well I think that is a MySQL approach, I've made some changes to your code and explained them:
$by_type1 = array(2=>"First", 3=>"Second+", 4=>"Final");
$counter = 2; //this counter represents type of interview (2-First, 3-Second+, 4-Final)
// Open connection first.
global $conn;
$conn->open();
// Using key => value array gets code simple
foreach ($by_type1 as $counter=>$type1)
{
$table_row = '<tr><td class="rborder">'.$type1.'</td>';
foreach ($row as $rec)
{
$id=$rec['id'];
$qry2 = "SELECT
CONCAT( r.fname, ' ', r.lname ) AS rname,
ch.status_id as Type,
count(ch.status_id) as number
FROM candidateJoborderHistory ch
LEFT JOIN candidates_info c ON ch.candidate_id = c.candidate_id
LEFT JOIN recruiters r ON c.recruiter_id=r.recruiter_id
LEFT JOIN interviewtypes i ON ch.interview_id = i.interview_id
WHERE c.recruiter_id = $id
AND UNIX_TIMESTAMP(ch.date_interview)
BETWEEN 1401667200 AND 1402099200
AND ch.status_id = $counter
GROUP BY ch.status_id";
$res = $conn->prepare($qry2);
$res->execute();
// Loop to get data...
while($row_x = $res->fetch(PDO::FETCH_ASSOC))
{
$table_row .= '<td>'.$row_x['number'].'</td>';
}
}
$table_row .='</tr>';
echo $table_row . "\n";
}
$conn->close();
Code isn't tested but if you have any doubt just ask. Hope it helps!
References:
Prepared Statements
Executing Statements

Student Position ranking in mysql

I have a project on student ranking. The sample school does three terminal exam in a year. I created three different tables for each terminal exam, (i.e. firstermsar for first, secondtermsar for second, thirdtermsar for third term respectively).
Table structure is like this:
id studentid matca1 matca2 matexam engca1 engca2 engexam
1 2 15 14 40 12 10 60
2 1 10 5 56 9 13 35
3 4 11 9 45 14 17 40
4 5 14 1 50 20 0 60
Students with id 4 and 5 are in class1 while students 2 and 1 are in in class2. I have a seperate table for classes and also seperate table for student profile info.
Now, I already output the result slip but without ranks which looks like this
StudentId: 2 Full Name: Fawaz James Class: Pry 2 Overall Position: -
1stAss 2ndAss ExamScore Grade Position Rmks
Mark Obtainable 20 20 60
English 12 10 60 A - Excellent
Mathematics 15 14 40 B - V. Good
Though am a starter, and my code is a mess, its provided underneath. Moreover I need help with calculating the overall position on class basis and subject position on class basis. Please help me as my project depends on this for approval and am in my deadline week before I got introduced to stack Overflow.
$query = "SELECT * FROM firsttermsars
WHERE studentID=$stuID AND year=\"$_SESSION[year]\""; #27
$result = mysql_query($query)
or die ("Couldn't execute query.");
while ($row = mysql_fetch_array($result,MYSQL_ASSOC))
{
echo "<h2> First Term Stint Report Sheet for $namet during the SESSION $year</h2>";
echo "<table class='table1'>";
echo "<tr>";
echo "<td></td>";
echo "<td><b>1st Assessment</b></td><td><b>2nd Assessment</b></td>
<td><b>Mid Term<br />Exam</b></td><td><b>Mid Term<br />Total Score</b></td><td><b>Grade<br />Point</b></td></tr>";
echo "<tr> <td><b>Mark Obtainable</b></td><td><b>30</b></td><td><b>20</b></td><td><b>50</b></td><td><b>100</b></td><td><b>||=||</b></td></tr><tr>";
$tetal = $row['thirdengtest']+$row['thirdengexam']+$row['eng1'];
if ($tetal >="1") {
$q2 = "1";
$sq2 = "100";
echo "<td>English Language: </td>";
echo "<td>{$row['eng1']}</td><td>{$row['thirdengtest']}</td><td>{$row['thirdengexam']}</td> <td>";
$total1 = $row['thirdengtest']+$row['thirdengexam']+$row['eng1'];
echo $total1."</td><td>";
if ($total1>="75")
echo "A1";
elseif ($total1>="70")
echo "B2";
elseif ($total1>="65")
echo "B3";
elseif ($total1>="60")
echo "C4";
elseif ($total1>="55")
echo "C5";
elseif ($total1>="50")
echo "C6";
elseif ($total1>="45")
echo "D7";
elseif ($total1>="40")
echo "E8";
elseif ($total1>="1")
echo "F9";
elseif ($total1=="0")
echo "-";
else
echo "F";
echo "</td></tr>";
}
$tetal = $row['thirdmathtest']+$row['thirdmathexam']+$row['math1'];
if ($tetal >="1") {
$q3 = "1";
$sq3 = "100";
echo "<tr>";
echo "<td>Mathematics </td>";
echo "<td>{$row['math1']}</td><td>{$row['thirdmathtest']}</td> <td>{$row['thirdmathexam']}</td> <td>";
$total2 = $row['thirdmathtest']+$row['thirdmathexam']+$row['math1'];
echo $total2."</td><td>";
if ($total2>="75") echo "A1"; elseif ($total2>="70") echo "B2"; elseif ($total2>="65") echo "B3"; elseif ($total2>="60") echo "C4"; elseif ($total2>="55") echo "C5"; elseif ($total2>="50") echo "C6"; elseif ($total2>="45") echo "D7"; elseif ($total2>="40") echo "E8"; elseif ($total2>="1") echo "F9"; elseif ($total2=="0") echo "-"; else echo "F";
echo "</td></tr>";
}
?>
I hope you can help me like this, and hope is not complicated. I wanted to add the picture of the output but its complaining i don't have the required reputation
Firstly, in the database, make a new column for total('Total') and ('Grade'), and when you are submitting the marks details to your database, add the marks and grade and then submit the total to the database, instead of calculating them while retrieving the information.
Second, when you are selecting students from the database, use the SQL command:
SELECT * FROM firsttermsars ORDER BY Total DESC
More info on ORDER BY
This will automatically return the list of students in descending order of their total marks.
Similarly, for subject ranking, you can have a separate table, where ranking is done on subject marks
Then, while retrieving the data,
<table>
<?php
while ($i<$num) //num is number of rows
{
?>
<tr><td><?php echo mysql_result($result,$i,"Name"); ?></td>
//... Similarly for all clumns
<?php
}
?>
</table>
This should make the table with all students ranked according to their total marks. Similarly you can make a table for ranking by subject marks.
This is how i would solve the problem. Hope I helped!
Although i am late, but it may help some one.
First of All you should calculate Obtained marks and store in database table.
For simplicity i am showing just 3 column.
Id Name Obtained
1 A 100
2 B 58
3 L 88
4 F 102
5 C 99
Insert the row in table , then run this query to get Position of student.
SELECT id, name, Obtained, FIND_IN_SET( score, (
SELECT GROUP_CONCAT( score
ORDER BY score DESC )
FROM scores )
) AS position
FROM scores
WHERE id = 5
Detail here https://dba.stackexchange.com/questions/13703/get-the-rank-of-a-user-in-a-score-table

Categories