I'm still a novice with PHP and MySQL but willing to learn and now I'm in need of help after three days of tinkering.
First, to help you understand my db structure, I have a MySQL db table named "o70vm_invoices_items" and I'm trying to loop through the results that are for each invoice_ID. Each item in the items table has a PK (o70vm_invoices_items.id) and the invoice_ID column is a link to another table (invoices).
In the items table, for example, some invoices would have one item, others could have two or three items. I'm feeling quite challenged with how to loop through to display all of the items (o70vm_invoices_items.name) associated with each invoice.
Here is my MySQL query statement:
$queryItems = "SELECT
o70vm_invoices_items.id AS 'Item_ID',
o70vm_invoices_items.invoice_id AS 'Invoice_ID_on_Items',
o70vm_invoices_items.name AS 'Program',
o70vm_invoices_items.value AS 'Fee',
o70vm_invoices_items.amount AS 'Qty',
o70vm_invoices_items.desc AS 'forWeek',
GROUP_CONCAT(o70vm_invoices_items.desc SEPARATOR ' & ') As 'forWeekGroup',
ROUND(SUM((o70vm_invoices_items.value)*(o70vm_invoices_items.amount)),2) AS 'INV-TOTAL'
FROM o70vm_invoices_items
WHERE o70vm_invoices_items.invoice_id = $invoiceID
GROUP BY o70vm_invoices_items.invoice_id";
As you can see, I'm searching the results from INVOICE_ID. This part works great. I get these results to display easy. The problem is I'm looking to display each value in the "o70vm_invoices_items.name" column for the selected Invoice ID AND I can only display one item.
Here is my attempt to loop through the results and display the info:
// storing the result of this MySQL query
$resultItems = mysql_query($queryItems) or die(mysql_error());
echo "<table><tr>";
while($rowItems = mysql_fetch_array($resultItems))
{
echo "<td>";
echo "<input type='text' title='' name='name' id='name' value='". $rowItems['Program']. "' /><br>";
echo "</td>";
}
echo "</tr></table>";
Again, I can only get the result of one item, not all the items. Any help, very much appreciated. I think I may need a different way to write an Array perhaps. Also, as you can see, I'm displaying it in a input tag that I am hoping I will later be able to EDIT the content.
PLEASE NOTE: Once I have this figured out, I will also need to do the same for Fee and Qty columns as well.
Firstly I would rewrite the sql so that it appears easier to read, to do that assign an alias to the table and use that when referencing the fields. This is especially useful when you are joining multiple tables - each alias must be unique. In the case of your original sql because you are only drawing data from one table there is no need really for an alias nor to use the full table name as a prefix to the individual fields (ie: table.field ) - just the fieldname would have sufficed.
<?php
$queryitems = "select
o.`id` as 'item_id',
o.`invoice_id` as 'invoice_id_on_items',
o.`name` as 'program',
o.`value` as 'fee',
o.`amount` as 'qty',
o.`desc` as 'forweek',
group_concat( o.`desc` separator ' & ' ) as 'forweekgroup',
round( sum( ( o.`value` ) * ( o.`amount` ) ),2 ) as 'inv-total'
from `o70vm_invoices_items` o
where o.`invoice_id` = '$invoiceid';";
// storing the result of this MySQL query
$resultItems = mysql_query( $queryItems );
if( $resultItems ){
echo '
<table>
<tr>
<th scope="col">ID</th>
<th scope="col">Program</th>
<th scope="col">fee</th>
</tr>';
$id=0; /* Each field / element that has an id must have a unique id ~ use a counter to achieve this */
while( $row = mysql_fetch_object( $resultItems ) ){
$id++;/* Increment the id counter */
echo '
<tr>
<td>'.$row->item_id.'</td>
<td>
<input type="text" title="'.$row->program.'" name="name" id="name'.$id.'" value="' . $row->program. '" />
</td>
<td>'.$row->fee.'</td>
</tr>';
}
echo '
</table>';
} else {/* Do not give away too much information and degrade gracefully */
echo 'Sorry, there was an error retrieving relevant information from the database';
}
?>
Your query contains these two lines. Together they guarantee you'll get only one row in your resultset.
WHERE o70vm_invoices_items.invoice_id = $invoiceID
GROUP BY o70vm_invoices_items.invoice_id
Your WHERE line filters your table so the resultset only contains rows for a particular invoice_id value. Then, GROUP BY summarizes the information for that particular value in one result-set row.
From your question it sounds like you have multiple items per invoice, and you wish to show detail rows for the items. In that case you're going to need to group by the items, not the invoice_id.
Try this GROUP BY.
GROUP BY o70vm_invoices_items.id
And, you are using a very confusing nonstandard MySQL extension to the GROUP BY functionality. If you start working with more than one table, this will bite you hard. Read about it. https://dev.mysql.com/doc/refman/5.6/en/group-by-handling.html
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
A PHP page must show the content of a database's table. In another table, there is the value I will use to print the row accordingly and show as a child.
$result = pg_query($conn, "SELECT *,'SENT' as direction FROM table1 WHERE identification LIKE '%$identification%' AND expedition LIKE '$expedition' order by date DESC LIMIT '$limit' ");
This, inside a WHILE, will print this kind of table:
while ($row = pg_fetch_row($result)) {
$sql2 = pg_query($conn, " SELECT quantity FROM expedition WHERE identification='$row[2]' ");
$row2 = pg_fetch_row($sql2);
$color="white";
if ($row2[0] == "-1") { $color="red";}
if ($row2[0] == "1") { $color="green";}
if ($row2[0] == "0") { $color="grey";}
echo "<tr bgcolor=\"$color\">
<td><button class=\"btn btn-info\" type=\"button\" data-toggle=\"collapse\" data-target=\"#$row[2]\">+</button></td>
<td>row[0]</td>
<td>row[1]</td>
<td>row[2]</td>
<td>row[3]</td>
<td>row[4]</td>
<td>...and more</td>
</tr>";
echo "<tr><td colspan=9><div style=\"background-color:$color\" id=\"$row[2]\" class=\"collapse\">$row2[0]</div></td></tr> ";
I am using bootstrap to add a button that, once clicked, will open a hidden row with the content of $sql2. Query that I will print straight after the </tr>.
Notice the 1st query as row[] and the second query as row2[].
The problem:
If the second query contains more than 1 result and in all cases identification is not a PK (therefore there could be more), I am not able to print for each row the colour of its childs.
I need to extend the second query to manage a WHILE loop, in order to extract, through identification, all the values of its parent.
IF, sql2 contains -1 or 1 or 0, the parent and itself must be painted accordingly.
IF, sql2 contains different values, both of them must be painted red (as error).
The obvious choice would be to move the SQL2 at the end of the first WHILE, in this case I can have SQL2 with all the records I want.
just like using arrays or the FOR structure.
Stays though the fact that moving the code would not allow me to print all the rows, because html is wrote already.
In this case I believe I'd need Jquery to highlight the values once they are written already.
I do not know a thing of Jquery and I'd appreciate any suggestion or help.
Attached a image to show what I achieved, the green bar only contain 1 child as the code above. Forgive the ugly interface!
I'm currently having trouble trying to create a loop for my desired outcome.
I'm currently creating a student record card which stores numerous data of different students (fake students).
I have created a query which returns the relevant data I need (see picture one, phpmyadmin)
SELECT mods.mid, mtitle, credits, enrl.ayr
FROM stud, smod, mods, enrl
WHERE stud.sid = '154279' AND stud.sid = smod.sid
AND smod.mid = mods.mid AND stud.sid = enrl.sid
ORDER BY `enrl`.`ayr` DESC
As you can see by the results, there are attributes:
mid
mtitle
credits
ayr
I have ordered by ayr in decending order. I am trying to make a loop that will run through the return on this query and print out each row until the end of whatever the current year is. Almost grouping all rows with the same year e.g. '2001/02' into a sub table which I can then name and print.
As you can see by my second picture of the student records page, I need to be able to print all records for the one year, then create a new header for the next existing year and print all containing rows for that.
{EDIT}
PHP Code:
$query = "SELECT mods.mid, mtitle, credits, enrl.ayr
FROM stud, smod, mods, enrl
WHERE stud.sid = '154279' AND stud.sid = smod.sid AND smod.mid = mods.mid AND stud.sid = enrl.sid
ORDER BY enrl.ayr DESC
";
$scap = '';
$curYear = $row['ayr'];
if($result = $link->query($query)) {
while ($row = $result->fetch_assoc() && $row['ayr'] == $curYear) {
$scap .= "<table id=\"test\" style=\"width:100%\">
<tr>
<td> " . $row['mid'] . " </td> <td> " . $row['mtitle'] . "</td> <td> " . $row['credits'] . " <td> " . $row['ayr'] . "</td>
</tr>
</table>";
}$result->free();
}
Thanks in advance.
Let's say you commit to one query max for the whole page. Like I said in comments
I would have a variable, call it $curYear. Start it out as some junk
string. In your loop, if the cur year thing is different than
$curYear, create a new segment in your output but regardless update
$curYear variable
That was not meant to interfere with your existing source code (that much). It is just a sentinel to alert you to a year change (year/term whatever).
So it starts as some junk value, like "797fsdf*"
Now inside your while, remember, you have ALL the years coming in from that result set for all years.
Do what I said in that pink block above comparing that variable $curYear to
$row['ayr']
When those two values are different, time to do whatever HTML treatment you want (creating a new html table, a new div, who cares). Let's call this the separation thing.
Regardless, after you output the row, make sure you have set $curYear to $row['ayr']. Why is that important? Because the next loop you want to know if you need to do the separation thing.
The tricky part is if you are doing html tables, you have to close out the previous table (prior year) if you are not on your first year
I am at the end of my project, I have all the data from my database and everything is working fine I just can not work out how to display it in a table.
I have generated a table which is the (number of projects) * (the number of people).
The data I have collected is user_id, project_id and hours.
But how do I insert '6' (hours) into user_x's row in the column of the correct project?
I can only think to make x arrays (for the number of projects) of the length for the number of users and evaluate the project code to select the correct array and then use the user id to get the correct position to place the value and simply spit out the array into the td tag
This is incredibly messy, I wonder if I'm going about it completely wrong.
If this is indeed the best way I need to recursively create arrays and write code which references variables that might not even exist. Sounds insane to me
//for the length of projects create arrays that are the length of users and fill with 0's
for ($v = 0; $v < $rows_x; $v++){
$name = "variable{$v}";
$$name = array_fill(0, $rows_u, '0');
EDIT: What I am trying to do is show the number of hours that are booked to projects between two dates. I have gotten all the data correctly but now I need the data to land into a table so you can easily see which user booked to what project.
In an excel world I could use the project number to select the Y axis and the user id to select the X axis. However I don't know the best way to do this in php.
Surely creating an array for each project the length of the users and filling with data if there is data is not the best way.
I don't know if this is what you're looking for, but I insert my values into a table in the process of retrieving them.
You can echo the values into a <td> as long as they are in your SQL SELECT statement.
<table>
<thead>
<tr>
<th>Values1</th>
<th>Values2</th>
</tr>
</thead>
<tbody>
<?php
$sql = "SELECT value1, value2
FROM tbl_Values";
if (!$res = $link->query($sql)) {
trigger_error('Error in query ' . $link->error);
} else {
while ($row = $res->fetch_assoc()) {
?>
<tr>
<td>
<?php echo $row['value1']; ?>
</td>
<td>
<?php echo $row['value2']; ?>
</td>
</tr>
<?php
}
}
?>
</tbody>
</table>
This is the way I put data into my tables, without using arrays.
I'm trying to create a form that retrieves data from a database and then allows me to add data to one column for multiple entries.
Every entry has an ID, a lot of other fields, and a category. I am trying to add these categories for every ID in the database using one form.
I came up with the solution below, but (of course)this only inserts the LAST entry in the form, because the variable ID is changed with every new row.
The form I have now shows me what I want to see, but it does not save it the way I need it to.
The question is, (how) can I make a form that has all entries in the database with a dropdown menu next to it,
lets me select the right category from the dropdown, and save it to the database?
The form:
$result = mysqli_query($con,"SELECT * FROM aw");
while($row = mysqli_fetch_array($result))
{
echo '<tr><td><input type="hidden" name="ID" value="'.$row[ID].'."> '.$row[ID].'</td><td>';
echo '
<select name="cat" onchange="this.form.submit()">
<option value="C1">category1</option>
<option value="C2"">category2</option>
</select></td></tr>
';
}
?>
<tr><td><input type="submit" title="SAVE" ></td></tr>
</form>
The insert.php
$sql="REPLACE INTO aw (ID,cat)
VALUES
('$_POST[ID]','$_POST[cat]')";
if (!mysqli_query($con,$sql))
{
die('Error: ' . mysqli_error($con));
}
mysqli_close($con);
?>
I changed my code according to Tom's answer and I now have the following:
This does print the values like they should be, but it still saves only the last entry into the database. I'm sure I must be missing something here..
$name = $_POST['ID'];
$category = $_POST['cat'];
foreach( $name as $key => $n ) {
$sql="REPLACE INTO aw (ID,cat)
VALUES
('$n','$category[$key]')";
print "The id is ".$n.", category is ".$category[$key]."<br>";
}
First of all, use PDO::Mysql, the SQL functions you are using are a bit deprecated and do not focus much on security. At the moment your code is vulnerable to SQL injections and your output is sensitive to XSS attacks (always sanitize output).
I was wrong, MySQL is deprecated but MySQLi is not! I do prefer using PDO::Mysql because of the range of databases it supports (MySQLi only supports a MySQL database, PDO::Mysql supports many more)
Now to your original question, you can create a sort of array. By making name="ID" to name="ID[]" and name="cat" to name="cat[]".
Now you can do
$name = $_POST['ID'];
$category = $_POST['cat'];
foreach( $name as $key => $n ) {
print "The id is ".$n.", category is ".$category[$key];
}
The problem is your using the name elements regardless of how many rows..
So name="ID" & name="cat" needs to change on each row or have an array type
you could use something like name="ID[]" as this would append/ create an array to $_POST['ID']... but you still would want to change your SQL query to handle each of these.
EDIT
If i understand, you want to be able to identify a row from the table so you can use that in the database?? One way todo this is when creating the table.. Give the TR a id/name attribute that is the row id from the database.
Then can simply know by checking that if your using the select menu from row #4, you check the id/name attribute of the current row and you have your database id.
<tr id='my_row_1'>
<td class='colName'>John</td>
<td class='colPhone'>1111</td>
<td class='colOther'>....</td>
</tr>
<tr id='my_row_2'>
<td class='colName'>Bill</td>
<td class='colPhone'>2222</td>
<td class='colOther'>....</td>
</tr>
<tr id='my_row_3'>
<td class='colName'>Roger</td>
<td class='colPhone'>3333</td>
<td class='colOther'>....</td>
</tr>
With something like the above, Say i had a button in on of the columns... When i click on that button.. all i have todo is find the parent TR and get its id value.... Then explode it by "_" and get the last piece to have the id..
So your PHP would generate the id easily... Also, using a form would not be the best case here.. Using multiple forms within a table is... wasteful... sort of ..
I would suggest more so, having a button that simple calls a js function which will then post/ajax/jquery what you need from that row.
--- Trying to understand exactly what you need??