Firstly let me apologise for my vague question title, this is my first post on this site; after spending 2 days searching for the answer to my question (and getting quite close in some cases) I've hit a wall. Normally I can find everything I need from stackoverflow but this time I've run out of ways to word my question in the search bar.
I have a mysql table containing data for clothes (tbl_clothing) and in this table (I've simplified this for my problem) I have columns: style, colour_url, size, carton_price
The 'style' is for a particulate type of garment $row['style'] in the first sql statement comes from the initial request to the database to find out if the users choice is actually a valid choice (don't worry I've sanitized it, no direct user input is ever used!)
I am grouping by colour_url to create an array of all the colour variations for the chosen style. Incidentally the colour_url is also the actual url to the image file for that colour (used later). Yes this does mean that in the database there is repeating data, the colour_url is repeated as many times as there are sizes for that colour - I've inherited it and can't change that yet.
I then iterate over this array 'foreach' of the different colours and perform another DB lookup to select all sizes and prices for the chosen style and the current colour.
Still in the above foreach loop I perform a while loop to create a second array to hold the sizes and prices (multiple rows are returned from the DB).
Still in the above foreach loop I perform another foreach loop on the second array to create the table structure for outputting.
This is now screaming at me that it is not the best way of achieving what I'm tying to do.
Am I just over thinking this or is there a much simpler way of doing things? I've tried doing a single sql lookup to retrieve a multidimensional array all in one hit but then cant separate out the data into correct groups I've been over and over transposing arrays re-looping through the array creating other "reference" arrays all without any success.
The basic logic works like this:
1 style = many colours
1 colour = many sizes
1 size = 1 price
And i'm trying to get a table output (for each colour) like this:
_________________________________
| (IMG A) | Size(1) | Size(2) | Size(3) |
| colour_A | Price(1) | Price(2) | Price(3) |
|_________|_______________________|
_________________________________
| (IMG B) | Size(1) | Size(2) | Size(3) |
| colour_B | Price(1) | Price(2) | Price(3) |
|_________|_______________________|
Here is my code, it does the job but this cant be the best way to do it:
$sql = "SELECT colour_url FROM tbl_clothing WHERE style = '".$row['style']."' GROUP BY colour_url";
$result = $mysqli->query($sql);
$numRows = $result->num_rows;
if ($numRows != 0){
while ($rowS = $result->fetch_assoc()){
$aResults[] = $rowS['colour_url'];
}
$result->free();
foreach ($aResults as $k=>$v){
echo "<table><tr><td rowspan='2'><img title='' alt='' src='".$v."' /></td>";
$sql = "SELECT size, carton_price FROM tbl_clothing WHERE style = '".$row['style']."' AND colour_url = '".$v."'";
$result = $mysqli->query($sql);
$numRows = $result->num_rows;
if ($numRows != 0){
$aSizePrice = array();
while ($rowS = $result->fetch_assoc()){
$aSizePrice[$rowS['size']] = $rowS['carton_price'];
}
$sizes = "";
$prices = "";
foreach ($aSizePrice as $key=>$val){
$sizes .= "<td>".$key."</td>";
$prices .= "<td>".$val."</td>";
}
}
$result->free();
echo $sizes;
echo "<tr>".$prices."</tr>";
echo "</tr></table>";
}
}
?>
Any help would be a hugely appreciated, even just a point in the right direction, a different opinion or even a sarcastic comment will do at this point...
One thing i might recommend right off the bat, seperate your concerns. You are trying to get data right from the database into your view layer. Instead, get your data, compile it into memory, THEN, display it. It will make your problem easier to solve right off the start.
For example:
//Prepare the data receptacle
$data = array();
//Query to data to work with
$result = $mysqli->query("SELECT * FROM tbl_clothing WHERE style = '".$row['style']."'");
$numRows = $result->num_rows;
while ($rowS = $result->fetch_assoc()){
//Make sure our data can be stored correctly into our structure
if(!isset($data[$row['style']])){ $data[$row['style']] = array(); }
if(!isset($data[$row['style']][$rowS['colour_url'])){ $data[$row['style']][$rowS['colour_url'] = array(); }
if(!isset($data[$row['style']][$rowS['colour_url']['sizes'])){ $data[$row['style']][$rowS['colour_url']['sizes'] = array(); }
if(!isset($data[$row['style']][$rowS['colour_url']['prices'])){ $data[$row['style']][$rowS['colour_url']['prices'] = array(); }
//Store the price and size
$data[$row['style']][$rowS['colour_url']['sizes'][] = $rowS['size'];
$data[$row['style']][$rowS['colour_url']['prices'][] = $rowS['carton_price'];
}
//At this point we have our data, let's just show it
?>
<table>
<?php foreach($data as $style => $color_urls){ ?>
<?php foreach($color_urls as $color_url => $content){ ?>
<tr>
<td rowspan="2">
<img title="" alt="" src="<?php echo $colour_url; ?>" />
</td>
</tr>
<tr>
<?php foreach($content['sizes'] as $size){ ?>
<td><?php echo $size; ?></td>
<?php } ?>
</tr>
<tr>
<?php foreach($content['prices'] as $price){ ?>
<td><?php echo $prices; ?></td>
<?php } ?>
</tr>
<?php } ?>
<?php } ?>
</table>
This is just a quick draft, i might not have understood your question correctly, you'll have to fix the errors and the miscomprehensions yourself. At least you have a good start with this!
Well, let's start with your query. In your first query, you claim you're trying to get all of the colors for a given style. You can use the DISTINCT keyword for that
SELECT DISTINCT colour_url
FROM tbl_clothing
WHERE style = ?
But that's not what you're actually looking to get - you actually want all of the color/size combinations in your database for a given style, which you would likely want to select thusly:
SELECT colour_url, size, carton_price
FROM tbl_clothing
WHERE style = ?
Once you've done that, you want to parse it into a data structure. (you should be parameterizing your queries - I recommend the PDO library, so I'll show you how that would work).
<?php
$db = new PDO('connection', 'user', 'pass');
$query = $db->prepare('SELECT colour_url, size, carton_price
FROM tbl_clothing
WHERE style = :style');
$query->bindValue(':style', $row['style'], PDO::PARAM_STR);
$query->execute();
$results = $query->fetchAll(PDO::FETCH_ASSOC);
$clothes = array();
foreach($results as $result){
if(!isset($clothes[$result['colour_url']]))
$clothes[$result['colour_url']] = array();
$clothes[$result['colour_url']][$result['size']] = $result['carton_price'];
}
?>
Your results are now in a series of nested maps - from $clothes[$color], you get a map from size to price. $clothes[$color][$size] will net you the price of a specific color and size, and you can choose to print them that way:
<?php
foreach($clothes as $color => $prices) {
$sizeStr = '<td>' . implode('</td><td>', array_keys($prices)) . '</td>';
$priceStr = '<td>' . implode('</td><td>', $prices) . '</td>';
?><table>
<tr>
<td rowspan="2">
<img title="" alt="" src="<?=$color?>" />
</td>
<?= $sizeStr ?>
</tr>
<tr>
<?= $priceStr ?>
</tr>
</table><?php
}
?>
Your code now reads a lot closer to english, which will make it easier to debug, and easier to pas on to others.
Related
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
I know how to produce results one after another but how do you separate them? So in my sql I'm selecting * from table and limiting it to 4
$sql = "SELECT * FROM table limit 4";
$result = $conn->query($sql);
while($row = $result->fetch_assoc())
{$rows['id']=$row;};
$price = $row['price'];
I dont seem to get any result, any suggestions, sorry guys beginner
...<?php echo $id ?></font></span>
<h4><?php echo $price ?></h4></div>
<div class="planFeatures"><ul>
<li><h1><?php echo $id=2 ?></h1></li>//how do I echo the next id?
<li><?php echo $price2 ?></li> //also the next price which id now is also 2
//and so on......
How do I display the next increments results in a different area of the same page, within another div?
I do get results if I sql and re-select all over again (and say id=2) but I'm sure there is a better way of doing it because I've already got my 4 results with my limit.
It seems you are not saving the results from the query result properly. Each iteration of the loop overwrites the same bucket in the $rows array. Instead, you need to add elements to the $rows array; this will produce an indexed array. Then you can iterate over it and generate the HTML content.
<?php
// Perform query.
$sql = "SELECT * FROM table limit 4";
$result = $conn->query($sql);
// Fetch results
while (true) {
$row = $result->fetch_assoc();
if (!$row) {
break;
}
$rows[] = $row;
}
// Generate HTML content using $rows array.
?>
<table>
<thead>
<tr>
<th>ID</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<?php foreach ($rows as $row):?>
<tr>
<td>ID: <?php print $row['id'];?></td>
<td>Price: <?php print $row['price'];?></td>
</tr>
<?php endforeach;?>
</tbody>
</table>
I took some liberty in the above example and generated a simple HTML table. Of course you can modify this to generate whatever you want.
I hope I've interpreted your question accurately, apologies if not!
I want to construct an html table based on the returned results from the database. Assuming I have a table called constraints in my database and a column called riskName and it has these values: Security, Financial, Legal and Technical as shown in the image below. How do i loop through my database and come up with this table. I have tried different approach but no has worked. Here is my code so far:
<?php
error_reporting(0);
$optioner = 12;
$getObs = $db->prepare("SELECT * FROM constraints WHERE constraintsID = ?");
$riski->bindParam(1, $optioner);
$riski->execute();
$result = $riski->fetch(PDO::FETCH_ASSOC);
while($getObs->fetch(PDO::FETCH_ASSOC)){
echo "<tr><td>".($result['riskName'])."<td><tr>";
//...other code
}
?>
</tbody>
<?php };
?>
I'm not sure if this will give you the exact table you're looking for, but it should at least put you on the right lines. Also, you weren't keeping your variables the same and notice how $result is set in the while loop
$optioner = 12;
$riski = $db->prepare("SELECT * FROM constraints WHERE constraintsID = ?");
$riski->bindParam(1, $optioner);
$riski->execute();
?>
<form>
<table>
<tr> <th>i</th> <th>Importance</th> <th>How Much More?</th> <tr>
<?php
while($result = $riski->fetch(PDO::FETCH_ASSOC)){
echo '<tr>';
echo '<td>'. $result['riskName']).'<td>';
echo '<td>';
for ($i=1;$i<10;$i++){
//radio buttons go here
}
echo'<tr>';
//...other code
}
?>
Sorry I couldn't help more.
Hope this works for you.
My connection to my database was successful. I now have all of the data from a table stored as an array in a php variable named $data. I am trying to extract three rows from this variable and display them with html.
Here is what my code looks like (with the exception of the connection info being removed):
<?php
$data = mysql_query("SELECT * FROM specs")
or die(mysql_error());
while ($row = mysql_fetch_assoc($data)) {
$rows[] = $row;
?>
I know that I can pull individual data from this variable and insert it into html successfully by entering code like this (for example):
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td>Model: <?php echo $row['name'];?></td>
</tr>
</table>
But my problem is that I want to display three separate rows of data from the database as three individual columns in a html table. (Hope that makes sense)
I've looked into how to do this with foreach and while but am not quite sure where I'm going wrong.
I'm hoping someone might be able to shed some light on this as I have read about foreach loops, while, and am still stuck! I'm also hearing that mysql_query is deprecated but ruled out not using this since our webserver is still using an old version of php and mysql and is not planning to update anytime soon.
Sorry if I'm not all here in my post - it's late and I'm tired. Thanks for your help in advance! I'll keep an eye on this in case anyone has questions.
This will print the array in a table with each row being 3 elements of the array.
echo "<table>";
for ($i = 0; $i < count($rows); $i += 3) {
echo "<tr>";
for ($j = 0; $j < 3; $j++) {
if (isset($rows[$i+$j]) {
echo "<td>Model: {$rows[$i+$j]['name']}</td>";
}
}
echo "</tr>";
}
echo "</table>";
It's simpler to limit the SQL to three rows, and then echo all incoming rows directly, without first adding to an array. That would waste resources.
<?php
echo "<table>";
$data = mysql_query("SELECT * FROM specs LIMIT 3")
or die(mysql_error());
while ($row = mysql_fetch_assoc($data))
echo '<tr></td>', $row['name'], '</td></tr>';
echo "</table>";
?>
Ah, but now I see it's a year old question. I hope you learned a lot in the meantime.
I have these two objects:
$userinfo->pilotid;
$departures->total;
I'm trying to get $departures->total for specific pilotid in $userinfo = $userinfo->pilotid.
However, I'm not sure how can I link them so it echoes A for B. I have something like this but it does not display anything.
<?php echo $pilotid->$departures->total; ?>
Additionally, the first object is called like this:
$pilotid = Auth::$userinfo->pilotid;
This is the structure of the table where the objects are gathered from, using a query.
Stemming from the data provided by the OP, I am assuming, that $departures has a 1:n relationship with $userinfo, $userinfo being the 1 containing the pilotid.
So, in oder to find out how many departures that pilot had in total, there's two possible ways, one by using a subquery, which would mean something like this:
SELECT (SELECT COUNT(*) FROM `departures` WHERE `pilot_id` = ID) as total, * FROM pilots;
In this case, your total would be in the total column of your $userinfo query.
The second attempt makes use of actual PHP. In this scenario, you do the counting yourself.
First step: Getting the pilot information:
$userinfo = array();
while($row = fetch()) {
$row->total = 0;
$row->departures = array();
$userinfo[$row->pilotid] = $row;
}
These lines will give you the pilot data keyed to their IDs in an array.
Step two. Glueing the departures to the pilots.
while($row = fetch()) {
if(isset($userinfo[$row->pilotid])) {
$userinfo[$row->pilotid]->departures[] = $row;
++$userinfo[$row->pilotid]->total;
}
}
If this isn't what you're looking for, I will be needing more information from you, however like this you will be able to get the departures of the pilots either by making use of the total variable in the $userinfo object, or by simply calling count on the departures array.
Another variant, which keeps the actual departures and the pilots apart would look like this:
First step: Getting the pilot information:
$userinfo = array();
while($row = fetch()) {
$row->total = 0;
$userinfo[$row->pilotid] = $row;
}
These lines will give you the pilot data keyed to their IDs in an array.
Step two. Glueing the departures to the pilots.
$departures = array();
while($row = fetch()) {
if(isset($userinfo[$row->pilotid])) {
$departures[] = $row;
++$userinfo[$row->pilotid]->total;
}
}
I hope you will find these suggestions useful.
Edit:
After a few additional information from the OP, I suggest changing the query used to access the information in question.
This is the original code by the OP
$dep_query = "SELECT COUNT(pilotid) as total, depicao, pilotid FROM phpvms_pireps GROUP
BY depicao, pilotid ORDER BY total DESC LIMIT 5";
$fav_deps = DB::get_results($dep_query);
foreach($fav_deps as $departure)
{
$dep_airport = OperationsData::getAirportinfo($departure->depicao);
$pilotid = Auth::$userinfo->pilotid;
?>
<tr class="awards_table1">
<td width="10%"><?php echo $departure->depicao; ?></td>
<td width="10%"><img src="<?php echo Countries::getCountryImage($dep_airport->country); ?>" /></td>
<td width="60%"><?php echo $dep_airport->name; ?></td>
<td width="20%"><?php echo $pilotid->{$departures->total}; ?></td>
</tr>
<?php
}
?>
First thing we'll change is the query used to get the departures. Why fetch all the information, if we actually only want the one of the pilot in question?
$pilotid = $userinfo->pilotid; //As per Chat discussion
$dep_query = "SELECT COUNT(depicao) as total, depicao FROM phpvms_pireps WHERE pilotid = $pilotid GROUP BY depicao ORDER BY total DESC LIMIT 5";
This query will return the Top 5 of the departures from the different airports, which have been run by the pilot in question. As for the rest:
$fav_deps = DB::get_results($dep_query);
if(is_array($fav_deps)) { //For the general use
foreach($fav_deps as $departure) {
$dep_airport = OperationsData::getAirportinfo($departure->depicao); ?>
<tr class="awards_table1">
<td width="10%"><?php echo $departure->depicao; ?></td>
<td width="10%"><img src="<?php echo Countries::getCountryImage($dep_airport->country); ?>" /></td>
<td width="60%"><?php echo $dep_airport->name; ?></td>
<td width="20%"><?php echo $departure->total; ?></td> //Here is the actually changed Layout code
</tr>
<?php
}
} else echo "This pilot didn't have any departures yet.";
?>
With these alterations, your code should output the desired result. It is completely untested though. However it should give you the right idea.
I think what you need is this (note the curly brackets):
<?php echo $pilotid->{$departures->total}; ?>
Unless I'm misunderstanding the question...