PHP - put the student name and grade into suitable skill name - php

(1) class
(2) studentmark
(3) skill
PHP code:
<?php
//DB CONNECTION
//---(1)Get skillname---
$q = "SELECT skillName FROM skill ORDER BY skillName asc";
$r = mysqli_query($dbc, $q);
$num_rows = mysqli_num_rows($r);
while($row = mysqli_fetch_array($r, MYSQLI_ASSOC))
{
$skills[] = $row['skillName'];
}
//---(2)Get classname---
$q1 = "SELECT className FROM class";
$r1 = mysqli_query($dbc, $q1);
$num_rows1 = mysqli_num_rows($r1);
while($row1 = mysqli_fetch_array($r1, MYSQLI_ASSOC))
{
$className[] = $row1['className'];
}
//---(3)Create table---
echo '<table border="1" style="border-collapse: collapse; text-align: center">';
echo '<tr>';
for($a = 0; $a < $num_rows; $a++)
{
echo '<th colspan="2">'.$skillName[$a].'</th>';
}
echo '</tr>';
for($b = 0; $b < $num_rows; $b++)
{
echo '<th>Student Name</th>';
echo '<th>Grade</th>';
}
echo '</tr>';
//---(4)Get student name and grade---
for($s = 0; $c < $num_rows1; $c++)
{
$q2 = "SELECT GROUP_CONCAT(sm.studentName) as studentName,
GROUP_CONCAT(sm.studentGrade) as studentGrade,
s.skillName
FROM studentmark sm
LEFT JOIN skill s ON sm.skillID = s.skillID
WHERE sm.className = '".$className[$c]."'
GROUP BY s.skillID";
$r2 = mysqli_query($dbc, $q2);
$num_rows2 = mysqli_num_rows($r2);
$value = array();
while($row2 = mysqli_fetch_array($r2, MYSQLI_ASSOC))
{
$value[] = $row2;
}
echo '<tr>';
for($d = 0; $d < $num_rows2; $d++)
{
echo '<td>'.$value[$d]['studentName'].'</td>';
echo '<td>'.$value[$d]['studentGrade'].'</td>';
}
echo '</tr>';
}
echo '</table>';
?>
From above code, my output is below:
I am almost finished. I can show the student name and grade in 1 row.
Now, the last thing I want to do is put them into suitable skill name like below:
I want to compare the $skills and s.skillname on $q2.
Below is my logic:
if($value[X]['skillName'] == $skills[X])
{
//put student name and grade inside
}
else
{
//empty cell
}
But I don't know where should I open for loop and put my logic in (4). Can someone help me?

So I'm definitely messing up your nice clean code for the sake of not looping through the data multiple times. I also display the classnames cause that seems like useful info.
I changed some variable names cause I found it easier to remember what each variable was for. Also, note how the student info query is only executed once. Normaly (read: I can't think of a reason why you wouldn't but I'm CMA), you want to minimize the number of times you query the database
The code below will replace the entire script you posted.
<?php
//DB CONNECTION
$dbc = // magic connection sauce you already have
// get skills and stash how many there are
$q_class = "SELECT skillName FROM skill ORDER BY skillName asc";
$r_class = mysqli_query($dbc, $q_class);
$num_skills = mysqli_num_rows($r_class);
// start table code so that we can echo the skillname headers
echo '
<table border="1" style="border-collapse: collapse; text-align: center">
<thead>
<tr>
<th rowspan=2>Classes</th>';//header for class name column
$header = array();
while($row = mysqli_fetch_array($r_class, MYSQLI_ASSOC))
{
$skills[] = $row['skillName'];
// store both thead rows at the same time so that we can echo them out properly later
$header['first'][] = '
<th colspan="2">' . $row['skillName'] . '</th>';
$header['second'][] = '
<th>Student Name</th>
<th>Grade</th>';
}
echo '
' . implode($header['first']) . '
</tr>
<tr>' . implode($header['second']) . '
</tr>';
// clean-up
mysqli_free_result($r_class);
// get class names and stash how many there are
$classes = array();
$query_class = "SELECT className FROM class";
$r_class = mysqli_query($dbc, $query_class);
$num_classes = mysqli_num_rows($r_class);
while($row = mysqli_fetch_array($r_class, MYSQLI_ASSOC))
{
$classes[] = $row['className'];
}
// clean-up
mysqli_free_result($r_class);
echo '
</thead>
<tbody>';
// pull query out of loop so that you'll only have to execute it once.
$studentInfoQuery = "
SELECT
GROUP_CONCAT(sm.studentName) as studentName,
GROUP_CONCAT(sm.studentGrade) as studentGrade,
s.skillName,
sm.className
FROM studentmark sm
LEFT JOIN skill s ON sm.skillID = s.skillID
GROUP BY sm.className,s.skillID";
$r_students = mysqli_query($dbc,$studentInfoQuery);
$num_studentRows = mysqli_num_rows($r_students);
$studentRows = array();
while($row = mysqli_fetch_array($r_students, MYSQLI_ASSOC)) {
// with our query, we only find 1 cell-pair per skill per class
$studentRows[$row['skillName']][$row['className']] = '
<td>' . $row['studentName'] . '</td>
<td>' . $row['studentGrade'] . '</td>';
}
// everybody do their share! // actually, more clean-up
mysqli_free_result($r_students);
for($j = 0; $j < $num_classes; $j++) {
echo "
<tr>
<th>" . $classes[$j] . "</th>";
for($i = 0; $i < $num_skills; $i++) {
// always echo out a cell, even if we have student info for it
// example: if(isset($studentRows['Listening']['1A'])) echo it out else echo cell
if(isset($studentRows[$skills[$i]][$classes[$j]]))
echo $studentRows[$skills[$i]][$classes[$j]];
else
echo "
<td colspan=2>No skill-class-student value</td>";
}
echo "
</tr>";
}
echo '
</tbody>
</table>';
?>
Results:

You are doing fine(although the things can be optimized) up to the last loop of step 4 in your design.
The problem you face right there is that you have a set of results which represent each class in it's rows. Now you need to spread them out in to skill table, importantly, without leaving vertical gaps.
The solution is to do it in a two dimension array in the memory and then create the table from it - because each cell in the memory is easily addressable than cells in an html table.
Memory table is going to be something like this:
|Skill 1 | Skill 2 | Skill3|
|stdnt 1 |stdnt 2,3|stdnt 4|
| | |stdnt 5|
Please note how I have used array_search to get the index of a particular skill and use it in array_push to insert the student in to the correct child array. Then I have just translated it in to an HTML table
I'm replacing your last loop with the following code:
//This is our memory table. Let's create it and add number of child arrays
//equal to number of skills.
$memTable = array();
for ($i = 0; $i <= sizeOf($skills) - 1; $i++) {
$memTable[$i] = array();
}
//Lets spread out your student information in to this 2d array now
foreach ($value as $student) {
//Get the index of the skill
$skillIndex = array_search($student['skillName'], $skills);
//Now go to appropriate child array and insert your student there
array_push($memTable[$skillIndex], $student);
};
//Lets create the table now
$emptyCount = 0;
$currentRow = 0;
//Do until all the skill arrays are empty for a row
while ($emptyCount < 3) {
echo "<tr>";
$emptyCount = 0;
foreach ($memTable as $skillLevel) {
if (sizeof($skillLevel) - 1 < $currentRow) {
$emptyCount ++;
echo "<td>&nbsp</td>";
echo "<td>&nbsp</td>";
}
else {
echo "<td>" . $skillLevel[$currentRow]['studentGrade'] . "</td>";
echo "<td>" . $skillLevel[$currentRow]['studentGrade'] . "</td>";
}
}
$currentRow++;
echo "</tr>";
};
Please note that the skills will be rendered in the table according to the order they are in the $skills array. Please ask me questions if there is any place that is not clear to you. You might need to adjust some String names to adopt in to your code.
UPDATE
while ($emptyCount < sizeof($skills)) is more accurate.

Related

Distinguish between elements and last element of array

Im creating tablerows based on the number of the array colours:
$query = mysql_query("SELECT * FROM things);
$num = mysql_num_rows($query );
$colours = array ();
if($num)
{
for ($i = 0; ($row = mysql_fetch_assoc($query)); ++$i)
{
$colours[$i] = $row["colours"];
}
}
$arrlength = count($colours);
for ($i = 0; ($i < ($arrlength)); ++$i){
echo "
<tr class='border_bottom'><td>".$colours[$i]."</td></tr>
";
}
So, if colours is, lets say, equal to 8, 8 table rows with the class border_bottom are created.
border_bottom is used by CSS to add a border to the bottom of each tablerow.
What I need is some PHP help: I need code which checks the array colours. The last element of the array has to go with an empty id since I dont want a border-bottom added to that very last tablerow. All other tablerows have to go with the border_bottom class, tho.
I was thinking of starting the code like that:
echo"
<tr class='
";
-->PHP code goes here<--
echo"
'>
<td>".$colours[$i]."</td></tr>
Try this:
<?php
$query = mysql_query("SELECT * FROM things");
$num = mysql_num_rows($query);
$colours = array();
if($num)
{
while($row = mysql_fetch_assoc($query))
{
$colours[] = $row["colours"];
}
}
$arrlength = count($colours);
for ($i = 0; $i < $arrlength; ++$i){
if($i < $arrlength - 1){
echo "<tr class='border_bottom'><td>{$colours[$i]}</td></tr>";
}else{
echo "<tr><td>{$someColor}</td></tr>";
}
}
Try the following code in your table row echo
echo "<tr"
.($i < $arrlength - 1 ? " class='border_bottom'" : "")
.">"
."<td>{$colours[$i]}</td></tr>";
You can actually do this while fetching the rows without needing to count how many there are, by reading ahead one row.
$previous_row = mysql_fetch_array(); // fetch the first row (if there is one)
while ($previous_row) {
if ($row = mysql_fetch_array()) {
// if another row is fetched, then the previous row was NOT the last row
echo '<tr class="border_bottom"><td>' . $previous_row['colours'] . '</td></tr>';
} else {
// otherwise, the previous row WAS the last row, and does not get the class
echo '<tr><td>' . $previous_row['colours'] . '</td></tr>';
}
$previous_row = $row; // Set the previous row to the current row
}

PHP dynamical duplicate Mysqli results set

I am attempting to populate 0 to many drop downs with the same results from a database table depending on a previous selection. it is working fine when 0 and 1 are selected but not when i am attempting to insert the result set into subsequent select elements. i am assuming it is a problem with the $row array position.
$homePlayers = "SELECT first_name, last_name, player_id FROM players WHERE team_name LIKE '$homeTeam%'";
$homePlayersQuery = mysqli_query($dbc, $homePlayers);
if (!$homePlayersQuery) {
echo 'err';
} else {
for ($i = 1; $i <= $homeTeamScore; $i++) {
echo "<select name='select-home-scorer-$i'>";
while ($row = mysqli_fetch_array($homePlayersQuery)) {
echo current($row);
echo "<option value='" . $row['player_id'] . "'>" . $row['first_name'] . " " . $row['last_name'] . "</option>";
}
echo "<option value='og'>Own Goal</option></select><br/>";
}
}
}
The problem you experience is that mysqli_fetch_array() reads data of the result set once. When you have read the last record, subsequent calls to mysqli_fetch_array() will return false.
You have 2 choices.
Firstly, you can read the records into an array and repeatedly parse the array.
while ($row = mysqli_fetch_array($homePlayersQuery)) {
$resultsArray[] = $row;
}
for ($i = 1; $i <= $homeTeamScore; $i++) {
foreach($resultsArray as $resultItem) {
do_something_here();
}
}
}
As a second option, you could rewind the pointer to the mysql result set so that you can start reading the results again.
for ($i = 1; $i <= $homeTeamScore; $i++) {
// Rewind the pointer to the start of the results
mysqli_data_seek($result, 0);
while ($row = mysqli_fetch_array($homePlayersQuery)) {
$resultsArray[] = $row;
}
}

how can I higlight the correct cell in PHP

I am trying to make a function in PHP which writes out a table, and looks in the database to find what cells should have info. the grid will always be the same size, but the content may be in different places.
I've gotten it to be able to look in the database, though it seems to only highlight the first cell, rather than the correct coordinates.
require("sql.php");
$sql = <<<SQL
SELECT *
FROM `maps`
WHERE `objpresent` = 1
SQL;
if(!$result = $db->query($sql)){
die('There was an error running the query [' . $db->error . ']');
} // ran the query
$xobj = array();
$yobj = array();
while($row = $result->fetch_assoc()){
//echo $row['x'] . $row['y'] . $row['object'] . '<br />';
$xobj[] += $row['x'];
$yobj[] += $row['y'];
}// get the rows
//find whether the row is obstructed
for($a=0; $a<=20-1; $a++) //rows (y)
{
for($i=0; $i<=25-1; $i++) //cols (x)
{
echo "<td>"; //between these write the apt content
// if (empty($xobj[$i]) || empty($yobj[$a]) ){
// echo '0';
//} //detect whether there is even a record for this space
if(!empty($xobj[$i]))
{
if(!empty($yobj[$a]))
{
echo $xobj[$i]; //debug
if($xobj[$i] == $i)
{
//echo $xobj[$i];
echo "A";
}
}
}
//echo "<td><img src='emptysym.png'></img></td>";
echo "</td>"; //add textual descriptions for now, add icons later
}
echo "</tr>";
}
this is my current(though rather messy) code.
if there is a row with the column x saying 2, and the column y saying 3, then it should put a letter at (2,3.
is it possible to fix this, or is there a better method for this?
Use a 2-dimensional array whose indexes are the x and y values from the database:
$xyobj = array();
while($row = $result->fetch_assoc()){
$xyobj[$row['x']][$row['y']] = true;
}
Then your output loop should be:
for ($y = 0; $y < 20; $y++) {
echo '<tr>';
for ($x = 0; $x < 25; $x++) {
echo '<td>';
if (isset($xyobj[$x][$y])) {
echo 'A';
}
echo '</td>';
}
echo '</tr>';
}

table + foreach - new column?

<?php
$values = array();
for($i=0;$i<100;$i++){
$values[$i] = "aaa" . $i;
} ?>
<table>
<?php
foreach ($values as $i => $val) {
echo "<tr><td>" . $val . "</td> </tr>";
} ?>
</table>
this generated me:
aaa1
aaa2
...
aaa50
...
aaa90
...
aaa100
how can I make two column?
aaa1 aaa50
aaa2 ....
... aaa90
aaa50 aaa100
but no:
aaa1 aaa2
aaa3 aaa4
... ....
aaa99 aaa100
a function
function sqlArr($sql){
$ret = array();
$res = mysql_query($sql) or trigger_error(mysql_error()." ".$sql);
if ($res) {
while($row = mysql_fetch_array($res)){
$ret[] = $row;
}
}
return $ret;
}
a code
$temp = sqlArr("SELECT value FROM table");
$data = array();
for($i=0;$i<50;$i++){
$data[] = array($temp[$i],$temp[$i+50]);
}
unset($temp);
a template
<table border='1'>
<? foreach ($data as $i => $row): ?>
<tr>
<? foreach ($row as $cell): ?>
<td><?=$cell?></td>
<? endforeach ?>
</tr>
<? endforeach ?>
</table>
Try if this works for you. Regardless of the format of the items contained in $values, it should print the array the way you want.
<?php
$size = count($values);
$halfSize = intval(ceil($size / 2));
for ($i = 0; $i < $halfSize; $i++)
{
$j = $i + $halfSize;
echo "<tr><td>" . $values[$i] . "</td>";
// If $size is odd, $halfSize is rounded up. This means that if we have
// 3 elements, it will try to access to $values[3], since $halfSize would
// be 2. The last second column element should be blank in this case.
// So, if $halfSize is odd, and $i is the last element, don't print an
// additional table cell.
if (!($i == $halfSize - 1 && $size % 2 == 1))
echo "<td>" . $values[$j] . "</td>";
echo "</tr>";
}
?>
The way that I would do this is to create two separate tables (each one column wide) and then include both of them in a single, two-columned table:
<?php
$list=array('a','b','c','d','e','f');
$midpoint=floor(count($list)/2);
$tableHeader='<table width="100%">';
$tableFooter='</table>';
$leftTable=$tableHeader;
$rightTable=$tableHeader;
for ($c=0; $c<$midpoint; $c++)
{
$leftTable.='<tr><td width="100%">'.$list[$c].'</td></tr>';
}
$leftTable.=$tableFooter;
for ($c=$midpoint; $c<count($list); $c++)
{
$rightTable.='<tr><td width="100%">'.$list[$c].'</td></tr>';
}
$rightTable.=$tableFooter;
$mainTable='<table><tr><td width="50%">'.$leftTable.'</td><td width="50%">'.$rightTable.'</td></tr></table>';
echo $mainTable;
?>
Add some CSS to remove padding around the sub-tables and borders etc and you should be good to go.
Since you already numbered it, just abstract it down:
a1 a51
a2 a52
...
a49 a99
a50 a100
is exactly the same as
a1 a1+50
a2 a2+50
...
a50 a50+50
This makes you having the following code:
echo "<table>";
for($i=1; $i<=50; $i++) {
echo "<tr><td>" . $i . "</td><td>" . ($i+50) . "</td></tr>";
}
echo "</table>";
Note: This requires you to let the table be generated this way. If it's actually not numbered like that, you would have to figure out another way to generate the abstract table in my listing 2 (just think about the index the entries have in relation to their left neighbor).

Mysql fetch array, table results

i'm pretty new to this and not sure how should i do it,
I've got a database with a column called "names"
how can i make it display in so?
<tr>
<td width="270px">Henry</td>
<td width="270px">Jeffrey</td>
<td width="270px">Hansel</td>
</tr>
<tr>
<td width="270px">Michelle</td>
<td width="270px">Jackson</td>
<td width="270px">Ivan</td>
</tr>
I only know how i should do it if the records goes one after another vertically.
$result = mysql_query('SELECT * FROM member');
while($row = mysql_fetch_array($result))
{
echo'
<tr>
<td width="270px">'.$row['names'].'</td>
<td width="270px">Jeffrey</td>
<td width="270px">Hansel</td>
</tr>';
Kinda stucked here...
Sorry i forgot to put this.
what i want is that it should loop the tags along. So i can have a 3 column table with infinite rows.
what bout this one? What if i want this to loop instead?
<tr>
<td><img src="images/ava/A.png" /></td>
<td>A</td>
<td width="2px" rowspan="3"></td>
<td><img src="images/ava/B.png" /></td>
<td>B</td>
</tr>
<tr>
<td>A</td>
<td>B</td>
</tr>
$row will update on each iteration of the loop:
$result = mysql_query('SELECT * FROM member');
echo '<tr>';
for($i = 0; $row = mysql_fetch_array($result); $i = ($i+1)%3){
echo '<td width="270px">'.$row['names'].'</td>';
if($i == 2)
echo '</tr><tr>';
}
echo '</tr>';
$result = mysql_query('SELECT * FROM member');
echo'<tr>'
while($row = mysql_fetch_array($result))
{
echo '<td width="270px">'.$row['names'].'</td>';
}
echo '</tr>';
$result = mysql_query('SELECT * FROM member');
echo '<tr>;
while($row = mysql_fetch_array($result))
{
echo '<td width="270px">'.$row['names'].'</td>';
}
echo '</tr>';
Lets say you have an array of the names called $names, then you could do what you wanted with code that looks something like this:
<tr>
<?php
foreach($names as $name) {
print "<td>$name</td>";
}
?>
</tr>
That would put all the names on the same row.
In order to start a new row say, every 3 names, you could put an if statement in the for loop like this:
// assume we have these variables available.
$row_number;
$max_cols = 3;
// this goes at the top of the foreach
if($row_number % $max_cols == 0) {
print '</tr><tr>';
}
You know accomplish this by assigning the row count before you start the variable and few flags to know initialized loop or started/ended loop.
$i = 1;
$initFlag = false;
$flag = "closed";
while($row = mysql_fetch_array($result)) {
if($i%3 == 0) $initFlag = false;
if($flag == "closed" && ($i == 1 || $i % 3 == 1)) {
echo "<tr>"; $flag = "started"; $initFlag = true;
}
echo '<td width="270px">'.$row['names'].'</td>';
if(!initFlag && $flag == "started" && $i % 3 ==0) {
echo "</tr>"; $flag = "closed";
}
$i++;
}
So most of these answers are going for the kludge. First, if all you want is the name in your resultset, then only ask for it. So rather than going with:
$result = mysql_query('SELECT * FROM member');
Instead go with:
$result = mysql_query('SELECT names FROM member');
Also, everyone seems to be ignoring the three column request, and that can be satisfied using a modulo to tell when to break the rows. We'll do a little magic to make sure you always close the row tag.
$row_count = 0;
while($row = mysql_fetch_array($result))
{
if( $row_count % 3 == 0 )
{
echo '<tr>';
}
echo '<td width="270px">'.$row['names'].'</td>';
if( $row_count % 3 == 0 )
{
echo '</tr>';
}
$row_count++;
}
I don't want to get too picky about your schema, but if you have a choice, it's better to name the table a plural like members rather than member, since you have a collection of rows, each one representing one 'member'. And unless your members have multiple names that column could probably best be called 'name' instead.

Categories