Group Query Results in PHP - php

I am using the following query to populate a table:
$result = mysql_query("SELECT vendor, part_number, machine, Sum(q_received) AS received, Sum(q_rejected) AS rejected FROM qa_parts Group by vendor, part_number, machine Order by vendor ASC");
I want to group the results by the Vendor then under the vendor display all the parts that have come from them and their details.
This is what I need it to do:
http://www.gen-techno.com/images/old.jpg
What it is doing now:
http://www.gen-techno.com/images/new.jpg
As you can see the the parts for Vendor O.P.S Products are not being grouped under that vendor like the parts are in the above example for Allied Electronics.
My table code as of now:
while($row = mysql_fetch_array($result))
{
echo "<h4>" . $row['vendor'] . "</h4>[fancy_table]<table>
<tr>
<th>Part Number</th>
<th>Quantity Received</th>
<th>Quantity Rejected</th>
<th>Machine</th>
</tr>";
echo "<tr>";
echo "<td>" . $row['part_number'] . "</td>";
echo "<td>" . $row['received'] . "</td>";
echo "<td>" . $row['rejected'] . "</td>";
echo "<td>" . $row['machine'] . "</td>";
echo "</tr>";
echo "</table>[/fancy_table]";}

During each loop you have to decide if it is time to draw the heading--you're going to list a new vendor. If it isn't a new vendor, you're still listing parts for the one you drew the last heading for, so you don't want the heading or to end the table.
$current_vendor = false;
while($row = mysql_fetch_array($result)) {
// listing a new vendor? Output the heading, start the table
if ($row['vendor'] != $current_vendor) {
if ($current_vendor !== false)
echo '</table>[/fancy_table]'; // if we're changing vendors, close the table
echo '
<h4>'.$row['vendor'].'</h4>[fancy_table]
<table>
<tr>
<th>Part Number</th>
<th>Quantity Received</th>
<th>Quantity Rejected</th>
<th>Machine</th>
</tr>
';
$current_vendor = $row['vendor'];
}
// output the row of data
echo '<tr>
<td>'.$row['part_number'].'</td>
<td>'.$row['received'].'</td>
<td>'.$row['rejected'].'</td>
<td>'.$row['machine'].'</td>
</tr>
';
}
echo '</table>[/fancy_table]'; // close the final table
On another note, you should start updating this code to use PDO. Obviously, you're in the middle of updating something that used to exist... make PDO a part of this update. The mysql_* functions are on the way to deprecation, and soon they'll be gone.
PDO is not hard to transition into, and it is MUCH easier now while you're already working on things than it will be later, when you're faced with the "it isn't broke, don't fix it" problem.
Here's a quick look at your code using the superior PDO DBA method:
$pdo = new PDO("mysql:host=localhost;dbname=database", '-username-', '-password-');
$sql = '
SELECT
vendor,
part_number,
machine,
SUM(q_received) AS "received",
SUM(q_rejected) AS "rejected"
FROM
qa_parts
GROUP BY
vendor,
part_number,
machine
ORDER BY
vendor ASC
';
$statement = $pdo->prepare($sql);
$statement->execute();
while ($order = $statement->fetch()) {
/* Put your table code here! */
}
Documentation
foreach - http://php.net/manual/en/control-structures.foreach.php
mysql_query (DEPRECATED) - http://php.net/manual/en/function.mysql-query.php
PDO - http://www.php.net/manual/en/book.pdo.php
PDO::prepare - http://www.php.net/manual/en/pdo.prepare.php
PDOStatement::fetch - http://www.php.net/manual/en/pdostatement.fetch.php
PDOStatement::execute - http://www.php.net/manual/en/pdostatement.execute.php

You need to split your loop into two parts. First part checks if you've got a new/different vendor, and sets up the "outer" setup. Then the inner part which dumps out that vendor's parts.
e.g.
$prev_vendor = null;
while($row = ...) {
if ($row['vendor'] != $prev_vendor) {
... new vendor stuff ...
$prev_vendor = $row['vendor']; // update vendor for next iteration
}
... dump this row's machine data ...
}

Related

SIMPLEST update to MYSQL from PHP

I am passing over a factory operations system to a new support team and I am writing a guide for that.
It has a VERY simple DB section tucked inside and I just want very basic set of procedures for demonstration to the team who are very IT literate but do not have any DB or PHP experience.
I have finished most of the guide but having a bit of a problem with a simple Quantity update procedure.
Be clear - I have no problem doing it but I have searched and searched for a simple answer and also everything I do seems just far more complex than it needs be. Can anyone assist with simplicity !
As the base exampler I am using the well tried
<?php
$con=mysqli_connect('localhost', 'bbbbbb', 'bbbbb', 'bbbbbbl') or die(mysql_error());
// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
$result = mysqli_query($con,"SELECT * FROM orders_products");
echo "<table border='1'>
<tr>
<th>Product ID</th>
<th>Product Name</th>
<th>Product Quantity</th>
</tr>";
while($row = mysqli_fetch_array($result))
{
echo "<tr>";
echo "<td>" . $row['products_id'] . "</td>";
echo "<td>" . $row['products_name'] . "</td>";
echo "<td>" . $row['products_quantity'] . "</td>";
echo "</tr>";
}
echo "</table>";
mysqli_close($con);
?>
which gives a simple table at the level I need
NOW all I want to demonstrate is how to update some or all of the Product Quantities in the list back to the MYSQL database. BUT AS SIMPLY AS POSSIBLE Without using individual "Edits" for each row. Apologies if this is too low level for you chaps !
NOTE: Edited to improve secrurity, but this does NOT negate the need for prepared statements to prevent other SQL injection attacks.
Wrap
<form method='POST' action='?'> around the table.
Replace
echo "<td>" . $row['products_quantity'] . "</td>";
With
$iProctId = $row['products_id'];
$iQuantity = $row['products_quantity'];
echo "<td>";
echo "<input type='text' name='product[{$iProductId}]' value='{$iQuantity}'/>";
echo "</td>";
In your script:
foreach( $_POST['product'] as $iProductId => $iQuantity ) {
mysqli_query( $con,"
UPDATE
orders_products
SET
products_quantity = ".(int)$iQuantity."
WHERE
products_id = ".(int)$iProductId."
");
}
Disclaimer
This script is simple, but not safe! To get it safe: mysqli_real_escape_string and mysqli_prepare
Enjoy :)

Search the results from a query

I have a site where members can mark other members as 'a favourite'. User are able to search the members table in various ways and I want to show from any of the results that are returned whether or not the users returned are favourites of the current user.
This is some very simplified code I have been using to try and get this query to work but I just can't figure it out. Whenever I add 'GROUP BY' to avoid duplicate results from my LEFT JOIN the 'if' statement does not work. The 'if' statment does work however, if I omit the 'GROUP BY' but I get all rows from members table and the favourites table. Thanks.
$result = mysqli_query($db_conx, "SELECT members.*, user_favourites.* FROM members LEFT JOIN user_favourites ON members.id = user_favourites.fav_id GROUP BY members.id");
echo "<table border=''>
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Email</th>
<th>A favourite of User</th>
</tr>";
while($row = mysqli_fetch_array($result)) {
echo "<tr>";
echo "<td>" . $row['firstname'] . "</td>";
echo "<td>" . $row['lname'] . "</td>";
echo "<td>" . $row['email'] . "</td>";
if ($visitor == $userid ){
$msgs = "x";
}
else { $msgs = "0";
}
echo "<td>". $msgs. "</td>";
echo "</tr>";
}
echo "</table>";
mysqli_close($con);
?>
I suggest to you, tu use 2 query's insted one. Simple query is a fast querys. If your site scale up, your query will be slow query and it cause performance problems.
Idea:
For one hand: SELECT FROM members, get all and put it inside array, key=member.id
$members[$row['member_id']]=$row;
On the other hand: SELECT * FROM user_favourites, and put it inside the previous array, refereced by the key fav_id use distinc if you have duplicates.
$members[$row['fav_id']]['favourites']=$row;
Perfect now you have all you need, an array with all information, iterate it.
JilianJ something like this:
<?
//Prepare
$all_users=array()
$query_users='SELECT * from user';
$query_favourites='SELECT * FROM user_favourites';
//Now I find all members information
$users=mysqli_query($db_conx,$query_users);
while($user = mysqli_fetch_array($users)) {
$all_users[$user['id']]=$user;
}
//Now I add favourite information to the users information
$favourites=mysqli_query($db_conx,$query_favourites);
while($favourite = mysqli_fetch_array($favourites)) {
$all_users[$favourite['fav_id']]['fovourite'][]=$favourite['fav_id'];
}
?>
<table>
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Email</th>
<th>A favourite of User</th>
</tr>
<? foreach ($information as $key=>$item) {?>
<tr>
<td><?=$item['firstname'];?></td>
<td><?=$row['lname'];?></td>
<td><?=$row['email'];?></td>
<td>
<? foreach($item['favourites'] as $key2=>$item2) { ?>
<p><?=$all_members[$item2]['name];?></p>
<? } ?>
</td>
</tr>
<? } ?>
</table>
Good luck

MySQL and PHP - make href remember previous variable

I am quite new to PHP, but come with some knowledge of JavaScript.
I am trying to construct a MySQL table which has sortable columns by header, which I managed figure out through looking around the web, etc; but then wanted the SQL query to use a WHERE clause which only shows rows that meet that clause (and it works), but the problem is that when I then sort the columns it goes back to the original value of the $catergory variable.
I hope that makes sense.
Could somebody please tell me what I am doing wrong and either if I need to change the SQL query or find a way to get the PHP to remember the reassigned value of $catergory, when I want to sort the columns afterwards?
Here is my code:
<?php
// Create connection
$con = mysqli_connect("host","user","password","database") or die("Some error occurred during connection " . mysqli_error($con));
$categoryFilter = array('boardroom', 'staffroom', 'kitchen');
$category = 'boardroom';
if (isset($_GET['categoryFilter']) && in_array($_GET['categoryFilter'], $categoryFilter)) {
$category = $_GET['categoryFilter'];
}
$orderBy = array('Image', 'Description', 'Light', 'Room');
$order = 'Image';
if (isset($_GET['orderBy']) && in_array($_GET['orderBy'], $orderBy)) {
$order = $_GET['orderBy'];
}
?>
<div class="catbuttons">
<ul>
<li>Boardroom</li>
<li style="height: 17px">Staffroom</li>
<li>Kitchen</li>
</ul>
</div>
<div class="index">
<table border='1'>
<tr>
<th>Image</th>
<th>Description</th>
<th>Light</th>
<th>Room</th>
</tr>
<?php
$result = mysqli_query($con,"SELECT * FROM officeindex WHERE Room='".$category."' ORDER BY ".$order)
or die("Error: ".mysqli_error($con));
while($row = mysqli_fetch_array($result)) {
echo "<tr>";
echo "<td>" , $row['Image'] , "</td>";
echo "<td>" , $row['Description'] , "</td>";
echo "<td><img src='" , $row['Light'] , "'></td>";
echo "<td>" , $row['Room'] , "</td>";
echo "</tr>";
}
echo "</table>";
?>
EDIT:
Thank you everyone, I have implemented your suggested solutions to my original question and changed the code above, but I am now having further difficulty. The purpose of my code is to construct an interactive product list of sorts. Now that I have the categories (thanks for pointing out the spelling mistake) working, I want the table, at first, to show all the categories, i.e. all the products in the list, before the user clicks on a specific category.
The other problem is that I can't work out what to do about cells which contain multiple categories (Some products fall into multiple categories).
I've thought about using arrays or loops or booleans or some kind to do both of the above, but my knowledge is limited to JavaScript and I'm a bit lost in PHP, even though there are similarities. Please forgive my ignorance.
I hope I have explained this clearly
Could anyone help me please?
The links in your tableheader only contain the orderBy parameter. If you want to keep the categoryFilter, you need to include it in the href of your headers.
For example:
<tr>
<th>Image</th>
<th>Description</th>
<th>Light</th>
<th>Room</th>
</tr>
For the category filter it's the other way around of course:
<li>Boardroom</li>
<li>Staffroom</li>
<li>Kitchen</li>
Also, as #K.K.Smith pointed out, you might want to replace catergory with category
In your links, You have to put the varaibles if they exists.
Example :
<a href="?categoryFilter=staffroom<?php if isset($_GET['orderBy'] echo '&orderBy=", $_GET['orderBy'];?>" />

Create multiple tables by cycling through a query

Here is my current code:
$varVeh=$_POST['Veh_num'];
$sql_HiScores = "SELECT
c.course_name as course,
e.distance as distance, e.score as score,
e.time as time, e.user as User
FROM hc_entries e
LEFT JOIN hc_course c on e.course=c.course_num
WHERE e.vehicle=$varVeh
ORDER BY course, score DESC";
$result_HiScores = mysql_query($sql_HiScores);
$sql_vehName="SELECT Veh_name FROM hc_vehicle_type WHERE Veh_num=$varVeh ";
$result_vehName = mysql_query($sql_vehName);
$vehName=mysql_fetch_assoc($result_vehName);
echo "<table><tr><th>Best Scores for ".$vehName['Veh_name']."</th></tr></table>";
echo "<table border='1'>";
echo "<tr><th>Course</th><th>Score</th><th>Distance</th><th>Player</th><th>Time</th></tr>";
while($row = mysql_fetch_array($result_HiScores))
{
echo "<tr>";
echo "<td>" .$row['course'] . "</td>";
echo "<td>" .$row['score'] . "</td>";
echo "<td>" .$row['distance'] . "</td>";
echo "<td>" .$row['User'] . "</td>";
}
echo "</table>";
What I think I have to do is create a query that selects * from e.course that builds an array. Then cycle through the existing query with the array results. Finally, I would like to display individual tables for each course and limit it to the top 5 results for each course.
Can anyone confirm or deny my logic, and point me in a direction?
First of all, you shouldn't be using the mysql_ functions, they're deprecated. At the least, you should switch to mysqli_ (a pretty easy switch), or better, learn how to use PDO. It's a bit different and more involved to switch, but your code will be better and safer for it.
With that out of the way: your logic is pretty accurate. Limiting your results to the top 5 results for each course in one query isn't something that's easily done with SQL to my knowledge, so your plan is good: query a list of courses, then cycle through them with your existing query, running it once for each course, with a LIMIT 5 to get the top 5.
You might as well keep the table generation within this loop as well, since it's a table-per-course. You'd want to move the VehName query out of the loop, since you only need to run that once.
Also, some unsolicited PHP advice: any text outside of the tags will just be output directly, so take advantage of its built-in-templating and alternative syntax to make your table generation code nicer:
<?php
/* Gather your data here... */
?>
<table>
<tr><th>Best Scores for <?php echo $vehName['Veh_name'] ?></th></tr>
</table>
<table border='1'>
<tr>
<th>Course</th>
<th>Score</th>
<th>Distance</th>
<th>Player</th>
<th>Time</th>
</tr>
<?php while($row = mysql_fetch_array($result_HiScores)): ?>
<tr>
<td><?php echo $row['course'] ?></td>
<td><?php echo $row['score'] ?></td>";
<td><?php echo $row['distance'] ?></td>";
<td><?php echo $row['User'] ?></td>";
</tr>
<?php endwhile; ?>
</table>
put the entire table html inside the while loop and add 'LIMIT 5' to the end of your query

Selecting table data with PDO statements [duplicate]

This question already has answers here:
How can I use PDO to fetch a results array in PHP?
(2 answers)
Closed 2 years ago.
I have a php script that selects data via mysql_, however recently I have been reading that PDO is the way to go and that mysql_ is becoming depreciated. Now I am converting that script to PDO.
My question is though, I am not using $_POST to select. I just want to select the entire table with all of its data so I enter this query :
$query = $dbh->prepare("SELECT * FROM students");
$query->execute();
$result = $query->fetchall(); // or you can just $result = $query as hakre proposed!
so then like I did with my old depreciated mysql_ version of the script I used the echo to echo a table with the data in it.
echo
"<table border='2'>
<tr>
<th>ID</th>
<th>A Number</th>
<th>First Name</th>
<th>Last Name</th>
<th>Why</th>
<th>Comments</th>
<th>Signintime</th>
</tr>"
;
foreach($result as $row)
{
echo "<tr>";
echo "<td>" . $row['id'] . "</td>";
echo "<td>" .$row['anum'] . " </td>";
echo "<td>" . $row['first'] . "</td>";
echo "<td>" . $row['last'] . "</td>";
echo "<td>" . $row['why'] . "</td>";
echo "<td>" . $row['comments'] . "</td>";
echo "<td>" . $row['signintime'] . "</td>";
echo "<td> <input type=\"button\" value=\"Start Session\"onClick=\accept.php?id=" . $row['id'] . "&start=true></td>";
}
echo "</tr>";
echo "</table>";
now using this, I can not get a single output to my table.
My question is am I missing something from my select statements? Or am I not fetching any rows? Also I the connection settings set in another script called connect.php that is required by init.php (at the top of all of my pages)
Edit : 1
Edited the code so it now works, also adding a picture to show others how it should look! Hopefully some one can put this to some sort of use!
You are doing too much actually:
$query = $dbh->prepare("SELECT * FROM students");
$query->execute();
$result = $dbh->query($query);
The problematic line is:
$result = $dbh->query($query);
Check with http://php.net/pdo.query, the parameter is a string, actually the SQL string you already use above, not the result value of a PDO::prepare() call.
For your simple query you can just do:
$result = $dbh->query("SELECT * FROM students");
Or if you like to prepare:
$query = $dbh->prepare("SELECT * FROM students");
$query->execute();
$result = $query;
The later is some boilerplate if you want to insert variables into the query, that's why you prepare it.
The next problem is with the foreach line:
foreach($result as $row);
You are terminating the loop immediately because of the semicolon ; at the end. Remove that semicolon so that the following angle-bracketed code-block becomes the body of the foreach-loop.
Your code is wrong:
$query = $dbh->prepare("SELECT * FROM students");
$query->execute();
$result = $dbh->query($query);
After executing a prepared statement, you can just call fetchAll() on it:
$query = $dbh->prepare("SELECT * FROM students");
$query->execute();
$result = $query->fetchAll();
The rest of your code will work fine once you remove the semicolon after the foreach.

Categories