Build a championship table in PHP from 3 MySQL tables - php

I am trying to display a championship table from the 3 tables I have in my MySQL database.
tbl_champ holds the championship name (nitro) and date (2015). tbl_rounds holds the round name (round1 so on) the date (01/01/2015 so on) and the champ_id. tbl_position holds the round_id, positions (1, 2, 3 etc) and racer_id (2, 4, 8 etc).
Inserting and updating the tables work great, but I cannot seem to get them to display as I want.
This is what I have:
echo '<table border="1">';
$sql_rou = mysql_query("SELECT * FROM `rounds`") or die(mysql_error());
while ($row_rou = mysql_fetch_array($sql_rou)) {
$rid = $row_rou[0];
echo '<th>' . $row_rou[1] . '</th>';
$sql_pos = mysql_query("SELECT `pos_user_id` FROM `positions` WHERE `pos_round_id`='$rid'") or die(mysql_error());
while ($pos_info = mysql_fetch_row($sql_pos)) {
echo '<tr>';
foreach ($pos_info as $field) {
echo '<td>'.$field.'</td>';
}
echo '</tr>';
}
}
echo '</table>';
But I get:
ROUND 1
[20]
[2]
ROUND 2
[2]
[20]
Any way to get the rounds next to each other, but keeping the []'s as they are?
(I've built the table in Excel).
Any ideas? Am I just thinking about this all wrong?

Take a look at where you close the brackets for the <th> entries. It should be about line 6 of your sample code. You have it at the bottom of the page. This will loop every result for each header value.
Also, you don't seem to have any <tr> in your <thead>. Think of your <th> as cells, like <td>, which need to be wrapped in a row.

Related

Grouping database entries into dynamic HTML tables

I have a database where teams will have multiple entries each with different locations. Each entry will have a team name. So for example, team1 might appear several times but each time the location will be different.
The structure of the DB is (each of these represents a column header):
team_name, first_name, last_name, location, arrival_time
My current working code creates HTML tables grouped by team name but currently only creates one row to show the first location and the time of arrival for the first location. I need this to dynamically create more rows to show all locations and arrival times for each team.
The desired result would look like this -
https://codepen.io/TheBigFolorn/pen/LqJeXr
But current result looks like this -
https://codepen.io/TheBigFolorn/pen/qgMppx
And here is an example of how the DB table might look -
https://codepen.io/TheBigFolorn/pen/daqJze
I've tried breaking up the echo and adding a second while loop before the row that I want to apply the above logic to but it seems to break everything. Any input on how I get this to work without having to use separate queries for each team would be very much appreciated. I'm new to php so please go easy on me :)
<?php
$leaders = "SELECT *, COUNT(location) FROM my_example_table GROUP BY team_name";
$result = mysqli_query($connect, $leaders) or die ("<br>** Error in database table <b>".mysqli_error($connect)."</b> **<br>$sql");
if ($result->num_rows > 0) {
// output data of each row
while($row = $result->fetch_assoc()) {
echo "
<div class='red-border'>
<h2>". $row["team_name"]. "<br><small>Total locations visited: ". $row["COUNT(location)"]. "</small></h2>
</div>
<div class='data-holder'>
<table>
<tr>
<th>Location</th>
<th>Time of arrival</th>
</tr>
<tr><td>". $row["location"]. "</td> <td>". $row["arrival_time"]. "</td></tr>
</table>
</div>
";
}
} else {
echo "0 results";
}
?>
Your problem is due to the GROUP BY, as you've probably realised. This is necessary in order to get a count per team, but causes the number of rows output to be only 1 per team - that's what grouping does. Fundamentally, running an aggregate query such as a COUNT or SUM is incompatible with also outputting all of the row data at the same time. You either do one or the other.
Now, you could run two queries - one to get the counts, and one to get all the rows. But actually you don't really need to. If you just select all the rows, then the count-per-team is implicit in your data. Since you're going to need to loop through them all anyway to output them in the HTML, you might as well use that process to keep track of how many rows you've got per team as you go along, and create the "Total number of locations" headings in your HTML based on that.
Two things are key to this:
1) Making the query output the data in a useful order:
SELECT * FROM my_example_table Order By team_name, arrival_time;
2) Not immediately echoing HTML to the page as soon as you get to a table row. Instead, put HTML snippets into variables which you can populate at different times in the process (since you won't know the total locations per team until you've looped all the rows for that team), and then string them all together at a later point to get the final output:
$leaders = "SELECT * FROM my_example_table Order By team_name, arrival_time;";
$result = mysqli_query($connect, $leaders) or die ("<br>** Error in database table <b>".mysqli_error($connect)."</b> **<br>$sql");
$currentTeam = "";
$locationCount = 0;
$html = "";
$teamHtmlStart = "";
$teamHtmlEnd = "";
if ($result->num_rows > 0)
{
while($row = $result->fetch_assoc())
{
//run this bit if we've detected a new team
if ($currentTeam != $row["team_name"]) {
//finalise the previous team's html and append it to the main output
if ($currentTeam != "") $html .= $teamHtmlStart.$locationCount.$teamHtmlEnd."</table></div>";
//reset all the team-specific variables
$currentTeam = $row["team_name"];
$teamHtmlStart = "<div class='red-border'><h2>".$currentTeam."<br><small>Total locations visited: ";
$locationCount = 0;
$teamHtmlEnd = "</small></h2>
</div>
<div class='data-holder'>
<table>
<tr>
<th>Location</th>
<th>Time of arrival</th>
</tr>";
}
$teamHtmlEnd .= "<tr><td>". $row["location"]. "</td> <td>". $row["arrival_time"]. "</td></tr>";
$locationCount++;
}
//for the final team (since the loop won't go back to the start):
$html .= $teamHtmlStart.$locationCount.$teamHtmlEnd."</table></div>";
echo $html;
}
else {
echo "0 results";
}
Here's a runnable demo (using some static data in place of the SQL query): http://sandbox.onlinephpfunctions.com/code/2f52c1d7ec242f674eaca5619cc7b9325295c0d4

How to show data in multiple html table a database query result

Hello I am trying to solve a problem. I've research and take time but unable to solve it sorry for that.
I am trying to show a database table query result in multiple table on a html page and every table should be a range i've put here 5 row at a table so if my query contain 29 row then it will show on 6 table and last table will contain 4 result the serial no of table will be correctly if first table 1st row is 01 then 2nd table 1st row will be 06. "the query result is not constant but it will depend on database record"
here is my code it shows only 1 table but not showing others table with result.
Thanks for your time. :)
$students = DB::table('mark_prc')
->select('student_roll','mark')
->where('cen_code', $c_code)
->where('sub_code',$subject)
->get();
$k=0; //counter for serial no
$m=5; // no of row each table
$c = count($students); // now have data on array after query 29
$p = ceil($c/5); // the data should be show on 6 tables now
for($i=0;$i<$p;$i++){
echo "<table>
<tr>
<th>SL</th>
<th>Roll</th>
<th>Mark</th>
</tr>";
for($j=$k;$j<$m;$j++){
echo '<tr>
<td>'.($k+1).'</td>
<td>'.$students[$k]->student_roll.'</td>
<td>'.$students[$k]->mark.'</td>
<tr>';
$k++;
}
echo '</table>';
}
Not sure why, but for($j=$k;is doing a reference assignment, so $j=&$k.
A workaround is to do -
for($j=($i*$m);$j<min((($i*$m)+$m),$c);$j++){
The ($i*$m), gets your start value, and ($i*$m)+$m) adds the 'no of row each table'
The min((($i*$m)+$m),$c) in $j<min((($i*$m)+$m),$c) is to max out the loop at $c.
So now your code would look like -
$students = DB::table('mark_prc')
->select('student_roll','mark')
->where('cen_code', $c_code)
->where('sub_code',$subject)
->get();
$m=5; // no of row each table
$c = count($students); // now have data on array after query 29
$p = ceil($c/5); // the data should be show on 6 tables now
for($i=0;$i<$p;$i++){
echo "<table>
<tr>
<th>SL</th>
<th>Roll</th>
<th>Mark</th>
</tr>";
for($j=(($i*$m));$j<min((($i*$m)+$m),$c);$j++){
echo '<tr>
<td>'.($j+1).'</td>
<td>'.$students[$j]->student_roll.'</td>
<td>'.$students[$j]->mark.'</td>
<tr>';
}
echo '</table>';
}

SQL group names as table header rows using PHP

I'm trying to output a dynamic table using PHP that looks something like this:
Paul 56
Paul 6
Paul 78
Paul 34
Paul 76
Mark 56
Mark 5
Mark 34
Mark 87
Mark 23
Mark 765
Basically what I want to output is something like this:
<table>
<tr colspan="2">Name: Paul</tr>
<tr><td>56</td><td>Edit</td></tr>
<tr><td>6</td><td>Edit</td></tr>
<tr><td>78</td><td>Edit</td></tr>
<tr><td>34</td><td>Edit</td></tr>
<tr><td>76><td>Edit</td></tr>
<tr colspan="2">Name: Mark</tr>
<tr><td>56</td><td>Edit</td></tr>
<tr><td>5</td><td>Edit</td></tr>
<tr><td>34</td><td>Edit</td></tr>
<tr><td>87</td><td>Edit</td></tr>
<tr><td>23/td><td>Edit</td></tr>
<tr><td>765/td><td>Edit</td></tr>
</table>
What my PHP code looks like so far:
<?php
$name_holder = null;
for($i=0;$i<count($data);$i++) {
if($name_holder != $data[$i]->name){
$name_holder = $data[$i]->name;
//not sure what to do here??
}
echo "<tr>";
echo "<td align='left'>".$data[$i]->name."</td>";
echo "<td align='left'>".$data[$i]->hour."</td>";
echo "</tr>";
}
?>
SQL
SELECT name,hour FROM checkin_tbl GROUP BY name ORDER BY name ASC;
You don't need to group your data at the database level. It is possible to do it that way, but for each group you'd need another SELECT to read the related data, and will result in excessive numbers of queries being sent to the database.
I've thus elected to read the data in using a straight query, which would be something like this:
SELECT name,hour FROM checkin_tbl ORDER BY name ASC;
I've not supplied the database code below, as it is not clear what database you are using (e.g. MySQL) or what interface you are using (e.g. PDO). I've thus emulated a data source using an array - I'm sure you can swap this out with a fetchAll() or a foreach() and a row fetch().
Thus, try something like this:
<?php
// Data from your database
$rawData = [
['Paul', 56],
['Paul', 6],
['Mark', 56],
['Mark', 5],
];
// Let's reformat this
$out = [];
foreach ($rawData as $pair)
{
$name = $pair[0];
if (!isset($out[$name]))
{
$out[$name] = [];
}
// Pop the value on the list
$out[$name][] = $pair[1];
}
// Use this to look at your structure
#print_r($out);
?>
<!-- Here's your rendering section -->
<?php foreach ($out as $name => $data): ?>
<tr colspan="2"><td>Name: <?php echo htmlentities($name) ?></td></tr>
<?php foreach ($data as $item): ?>
<tr><td><?php echo htmlentities($item) ?></td><td>Edit</td></tr>
<?php endforeach ?>
<?php endforeach ?>
My strategy is to format the data as much as possible outside of the template - your code and another answer here (at the time of writing) are mixing logic and layout excessively in my opinion, and you need to separate them out.
This is why I have switched to opening/closing PHP tags in the rendering section: this is broadly HTML with PHP snippets where dynamic output is required. You'll benefit from tag matching and syntax colouration in your IDE if you do it this way.
I've added htmlentities() in to protect against XSS.
Looking at the desired situation, there is absolutely no need for a GROUP BY.
In fact this is actually hindering your from displaying all records for a given person. You will end up with one row per person, filled with the last record for that person.
In order to get the situation you desire, strip the GROUP BY.
A PHP solution COULD be.
$name_holder = null;
for($i=0;$i<count($data);$i++) {
if($name_holder != $data[$i]->name){
$name_holder = $data[$i]->name;
echo "<tr><td colspan='2'>Name: " . $name_holder . "</td></tr>"
}
echo "<tr>";
echo "<td align='left'>".$data[$i]->hour."</td>";
echo "<td align='left'>edit</td>";
echo "</tr>";
}
You were well on the way to a correct solution.
Background info on Grouping and your problem:
A good explanation is found here: http://www.tutorialspoint.com/sql/sql-group-by.htm
A demo that it will not work can be tested on the w3schools demo database: http://www.w3schools.com/sql/trysql.asp?filename=trysql_select_groupby
All records:
SELECT CustomerId, ShipperId FROM [Orders] WHERE ShipperId = 1
Grouped:
SELECT CustomerId, ShipperId FROM [Orders] WHERE ShipperId = 1 GROUP BY ShipperId

Use 1 column as a header in a table with PHP and MySQL

I have a PHP file that displays the results of a SQL query in a table. The table lists items in customer orders. A sample table is below:
select * from v_orders:
order_number location order_stage item quantity
1 Patio1 3 17 2
1 Patio1 3 35 1
1 Patio1 3 13 6
2 Patio3 1 17 4
2 Patio3 1 15 1
2 Patio3 1 16 5
Columns order_number, location and stage are pulled from a single row in another table, so they're always the same. I want my PHP script to make a new HTML table every time it encounters a new order number. order_number, location, and stage will make up the first row of each table, and item and quantity will make up all subsequent rows. When the script finds a new order number, it starts a new table. In addition, each table will have a button at the bottom to update the order.
Here's how I want the final output to appear.
Order: 1 Location: Patio1 Stage: 3
Item: 17 Qty: 2
Item: 35 Qty: 1
Item: 13 Qty: 6
(button)Update Order 1
Order: 2 Location: Patio3 Stage: 1
Item: 17 Qty: 4
Item: 15 Qty: 1
Item: 16 Qty: 5
Here's the PHP I've written. The variable $new_table holds the HTML to build these tables. The script uses a familiar while loop to iterate through each row. When the current row has an order_number field that different from the previous row, it adds a button and to close off the previous table and adds and headers to start a new table:
<?php
include "../util.php"; //Includes the connect string $connect
$id = $_SESSION['id'];
$query = mysqli_query($connect,"SELECT * FROM v_orders WHERE waiter=$id AND order_stage <> 4 ORDER BY order_number");
//Placeholder to hold the current order in the row.
$current_order = 0;
//while loop to iterate through the query results
while($row=mysqli_fetch_array($query)){
if($row['order_number'] != $current_order){
//Add button to the previous table and close, then start a new table
$new_table .= '
<tr>
<td><button onclick="update(\'enter_order.php?order= '.$current_number.' \')">Modify Order</button></td>
</tr>
</table>
<table style="padding:20px;border:5">
<tr><th>Order Number: '.$row['order_number'].'</th><th>Location: '.$row['location'].'</th><th>Stage: '.$row['order_stage'].'</th></tr>';
//Set the placeholder variable to the current order number.
$current_number = $row['order_number'];
}
//Add item and quantity data. Note that this code runs with every iteration of $row
$new_table.='
<tr><td>'.$row['name'].'</td><td>'.$row['quantity'].'</td><td>'.$row['price'].'</td></tr>';
} //end while loop
//After the while loop, close the last table.
$new_table.= '
<tr>
<td><button onclick="update(\'enter_order.php?order='.$current_number.'\')">Modify Order</button></td>
</tr>
</table>';
//Finally, echo the new_table variable to the browser. It should be properly formed HTML.
echo $new_table; ?>
This works great. I get a nice self-contained table for each order. Except it puts a "modify order" button above the first table. How can I strip that out? I tried using the ltrim command as such:
$new_table = ltrim($new_table, '<tr>
<td><button onclick="update(\'enter_order.php?order= '.$current_number.' \')">Modify Order</button></td>
</tr>);
But the command got hopelessly confused by all the whitespace. Where you see a space or a tab, the ltrim command took out extra characters. I spent hours trying to remove all the white space and fit everything on one line. But that got me hopelessly confused because I got lost without any proper indentation.
Rather than fight with the ltrim command, I'd like to just change my whole algorithm. Is there some way I can add the right code to the end of each table (Move....) without sticking it all the way at the top of while loop?
Above the loop, you set the value of $current_order, but it isn't used in the loop. That's fine. This code depends on $current_number being undefined during the first loop. Your algorithm isn't bad, it just needs code specific to the very first loop to make it work.
while($row=mysqli_fetch_array($query)){
if (!$current_number) {//first loop, $current_number doesn't exist yet
$new_table .= '
<table style="padding:20px;border:5">
<tr><th>Order Number: '.$row['order_number'].'</th><th>Location:'.$row['location'].'</th><th>Stage: '. $row['order_stage'].'</th></tr>';
}
if(($row['order_number'] != $current_number) && ($current_number)){//won't fire on the first iteration
//Add button to the previous table and close, then start a new table
$new_table .= '
<tr>
<td><button onclick="update(\'enter_order.php?order= '.$current_number.' \')">Modify Order</button></td>
</tr>
</table>
<table style="padding:20px;border:5">
<tr><th>Order Number: '.$row['order_number'].'</th><th>Location: '.$row['location'].'</th><th>Stage: '.
$row['order_stage'].'</th></tr>';
}
//Add item and quantity data. Note that this code runs with every iteration of $row
$new_table.='<tr><td>'.$row['name'].'</td><td>'.$row['quantity'].'</td><td>'.$row['price'].'</td></tr>';
//Set the placeholder variable to the current order number.
$current_number = $row['order_number'];
} //end while loop
You should end the table and add the button only when you have the content in $new_table already.
if ($row['order_number'] != $current_number) {
if (strlen($new_table) > 0) {
$new_table .= '
<tr>
<td><button onclick="update(\'enter_order.php?order= '.$current_number.' \')">Modify Order</button></td>
</tr>
</table>';
}
$new_table .= '
<table style="padding:20px;border:5">
<tr><th>Order Number: '.$row['order_number'].'</th><th>Location: '.$row['location'].'</th><th>Stage: '.$row['order_stage'].'</th></tr>';
//Set the placeholder variable to the current order number.
$current_number = $row['order_number'];
}
Here is some tested code that does what you want.
It uses the 'read ahead' technique for the data rows. It simplifies the logic as you do things in the order the appear rather than trying to sort out what you did last.
This technique is to read a record before you start processing the data.
Process the record.
Read the next record.
PHP 5.3.18 on windows XP (XAMPP)
The comments try and explain what is happening.
Sample output:
Order Number: 1 Location: Patio1 Stage: 3
17 2 21.00
35 1 22.22
13 6 23.00
Modify Order
Order Number: 2 Location: Patio3 Stage: 1
17 4 31.00
15 1 32.00
16 5 21.00
Modify Order
<?php
session_start();
//..
$connect = mysqli_connect('localhost', 'test', 'test', 'testmysql');
// include "../util.php"; //Includes the connect string $connect
// $id = $_SESSION['id'];
$query = mysqli_query($connect,"SELECT * FROM v_orders ORDER BY order_number");
// Although it is a little clumsy, the code for while loops
// is easier if you use the 'read ahead' technique of the row data
// this means that changes cause the current processing to stop
$row = mysqli_fetch_array($query);
//while loop to iterate through all the orders...
while(isset($row['order_number'])) {
//Set the placeholder variable to the current order number.
$current_number = $row['order_number'];
// Start a new table...
echo '<table style="padding:20px;border:5">'
.'<tr><th>Order Number: '.$row['order_number']
.'</th><th>Location: '.$row['location']
.'</th><th>Stage: '.$row['order_stage'].'</th></tr>';
// write all the table rows for the current order
while ($row['order_number'] == $current_number) {
echo '<tr><td>'.$row['item'].'</td><td>'.$row['quantity'].'</td><td>'.$row['price'].'</td></tr>';
// read next row -- may be for a different order
$row = mysqli_fetch_array($query);
}
// Add button to the current table and close.
echo '<tr><td><button onclick="update(\'enter_order.php?order= '.$current_number.' \')">Modify Order</button></td></tr></table>';
} // end of all the orders
?>

Everything is Out of Order: Php - MySQL

I am trying to create a php script that gets values from a MySQL database, displays a header with the time_stamp that comes from an array, and a sub header with a value called "working_ra" with values underneath those categories. The values that go underneath both categories are being displayed in a table. I am sorting the values of the working_ra in the query so I can run a while loop saying that if they're not the same to display the next working_ra and continue echoing values. Here is my code:
foreach ($date as $i) {
echo "<pre>"."<h2>".$i."</h2>"."</pre>";
$result = mysqli_query ($con, "SELECT * FROM Signing WHERE value1 = 'Ings' AND time_stamp = '$i' ORDER BY working_ra");
$num_results = mysqli_num_rows($result);
$row = mysqli_fetch_array($result);
$desk = $row["working_ra"];
echo "var_desk starting value ","<b>", $desk,"</b>";
echo "<table border='1'>";
echo "<tr>";
echo "<td>", $row["first"],"</td>";
echo "</tr>";
while ($row = mysqli_fetch_array($result)) {
if ((string)$desk != (string)$row["working_ra"]) {
echo "</table>";
$desk = $row["working_ra"];
echo "var_desk next value ","<b>",$desk,"</b>";
echo "<br />";
echo "<table border='1'>";
}
echo "<tr>";
echo "<td>", $row["first"],"</td>";
echo "</tr>";
}
$result->free();
}
$con->close();
Everything works fine until it hits to the second "desk" name. Then the tables that are supposed to be with the next value get shifted to the next date. Here is what it looks like on the page:
aSFashagh, Jeremy, Jeremy, and Johnny are all supposed to be under (Phil, January 10 2013) but is shifted down into the next date and working_ra (Phil, January 20 2013). zffaA, andsdfdsggsdhj are all supposed to be under (Phil,January 20 2013) but are under (Phil, February 25 2013) instead. Whats weird is that the method did work WITHOUT trying to put all of the values in tables.
My assumption is that it could be the ordering of which the table tags are ending and starting, but I have tried numerous amounts of things and still cannot figure out what is wrong.
EDIT
Sorry its very confusing to say. But im trying to get it to where everything is shifted up the way its supposed to be. Where the values of "first" belong with their corresponding time_stamp and working_ra. For instance, the value of Johnny in the MySQL db has a value of working_ra - Phil and a value of time_stamp - January 10, 2013. However as you can see, Johnny is not underneath (Phil, January 10 2013) instead January 20, 2013. Its not the query thats the problem, it has something to do with the while loop and the table and I just can't figure it out.
The only two values that are correct are Zack and Why which have corresponding values of (working_ra = "Bob", time_stamp = "January 10, 2013")
I believe your problem is with the mysql row pointer. You already used mysqli_fetch_array once before the while loop therefore shifting the current mysql row to the next row.
This code
mysqli_data_seek($result, 0);
will reset the pointer.
Place it right before your while loop.
Figured out what the problem was. I needed to add a "/table" tag when the while loop breaks.

Categories