nested while loop stops after first iteration PHP - php

I'm fairly new to this so I am probably missing something very basic, but I am trying to write some PHP script. I want to normalize my main table of data, which is info on used cars, make, model, price, etc. So I have another table with all of the unique car manufacturers in, this stores the makeName with a unique id makeId In my script, I connect to the database, read in all of the data from the main table, run it as an SQL query, then store it as a variable. I do the same with the make table.
Then I try to run through a nested while loop to replace all of the strings in the main table in the Manufacturer column with the makeId from the make table so that I can link these two tables. It works for one iteration then stops, I've tried adding !==FALSE after the fetch_assoc in either and both while loops, but that gives me infinite loops I think. Here is my code...
<?php
include("conn.php");
$sqlAll= "SELECT * FROM carData";
$carDataResult = $conn->query($sqlAll);
if(!$carDataResult){
echo $conn->error;
die();
}
$sqlMake = "SELECT * FROM 000make";
$makeResult = $conn->query($sqlMake);
if(!$makeResult){
echo $conn->error;
die();
}
while ( $make =$makeResult-> fetch_assoc()){
$makeID = $make['makeId'];
$makeName = $make['makeName'];
while ($row = $carDataResult->fetch_assoc()){
$sqlUpdate="UPDATE carData SET Manufacturer = '$makeID'
WHERE Manufacturer='$makeName' AND Manufacturer IS NOT NULL";
$res = $conn->query($sqlUpdate);
if(!$res){
echo $conn->error;
die();
}
}
}
?>

About 10 mins after I posted the question, after staring at this all day, I realised that I didn't need a nested loop at all and wrote the code below, which is clunky but it solved the problem, but I like your solution better #TangentiallyPerpendicular...thanks for your help guys...
while ($make =$makeResult-> fetch_assoc()){
$makeID = $make['makeId'];
$makeName = $make['makeName'];
$sqlUpdate="UPDATE carData SET Manufacturer = '$makeID'
WHERE Manufacturer='$makeName' AND Manufacturer IS NOT NULL";
$res = $conn->query($sqlUpdate);
if(!$res){
echo $conn->error;
die();
}
}

As a general rule, reading a result set and looping through it to run successive queries is the wrong way to deal with this sort of problem. You can do it all in a single query:
update carData set `Manufacturer` = (select `makeId` from `000make` where 000make.makeName=carData.Manufacturer)
Your entire program becomes:
<?php
include("conn.php");
$sqlAll= "update carData set `Manufacturer` = (select `makeId` from `000make` where 000make.makeName=models.Manufacturer) ";
$carDataResult = $conn->query($sqlAll);
if(!$carDataResult){
echo $conn->error;
die();
} else {
echo "Update Successful"
}
As an aside, I'd create a new column (called, perhaps, makeId) in your carData table and insert the data there rather than overwriting the Manufacturer column. That way you retain the Manufacturer column if something goes wrong. You can drop that column later.

Related

Left joining multiple tables using the same table alias (only one will load based on condition)

I've got a list of tables that we use in our database for products stored in its own database. I set up an array of "tables" using this code.
$TABLES_QUERY = $db1q->query("SELECT t.table FROM Product_Tables as t WHERE t.visibility = 1 ORDER BY t.sort_order ASC") or die ('Unable to execute query. '. mysqli_error($db1q));
if ($TABLES_QUERY->num_rows > 0) {
while ($TABLES = $TABLES_QUERY->fetch_assoc()) {
$query_tables_array[] = $TABLES['table'];
}
}
What I am trying to do in our inventory system is pull data from the correct table without having to write out every single table and each table have a unique table alias. That would mean everytime a new product table is created, the code would have to be updated. I would much rather just add that table into the tables database, and the code still works....
Below is the code I was attempting to use...
if (!empty($query_tables_array)) {
foreach ($query_tables_array as $val) {
$SKU_QUERY .= " LEFT JOIN ". $val ." as ptbl ON
(s.product_table='". $val ."' and ptbl.id = s.part_number_id)";
}
}
There are conditions applied to the table so only one should be called, but its throwing the error
Not unique table/alias: 'ptbl'
Is there a proper way of doing this where it will work?
I'm using ptbl in the SELECT query to get data from the LEFT JOIN'D table so I'd prefer to be able to do this similarly to how I am trying to if there is a way.
This is probably quite confusing, so please let me know if you have any additional questions.
the problem is that $query_tables_array has multiple items and you can use an alias only once in the same query. I would change this to
if (!empty($query_tables_array))
{ foreach ($query_tables_array as $val)
{ $SKU_QUERY .= " LEFT JOIN ". $val ."
ON (s.product_table='". $val ."' and $val.id = s.part_number_id)";
}
}

Best way to identify a mysql changed "group by" field value in a statement fetch in php?

I have a sql query in my php:
$sql = "SELECT * FROM orderTaken WHERE orderStatus='10' GROUP BY orderId ORDER BY orderTakenTime DESC";
Now, I have to echo back several HTML tables based on different orderIds, so basically if the orderId is changed, a new HTML table will be created and contains the info of all the things under this orderId. This is what I have done(kinda pseudocode, please ignore the syntax error. My real code is far more complicated but the idea is here: set an oldOrderId and check it with the newly fetched orderId and see if the orderId is changed):
$sql = "SELECT * FROM orderTaken WHERE orderStatus='10' GROUP BY orderId ORDER BY orderTakenTime DESC";
$stmt = $pdo->prepare($sql);
$stmt->execute();
$count = $stmt->rowCount();
for ($i = 0; $i<$count + 1; $i++ ){
if ($row = $stmt->fetch()){
$orderId = $row["orderId"];
$2ndField = $row["2ndField"];
$3rdField = $row["3rdField"];
...
// check if $oldOrderId is set
if (isset($oldOrderId)){
// and compare, if the orderId changes, end the table and create a new one
if ($oldOrderId != $orderId){
echo "</table><br>";
echo "<table><tr><th>...</th></tr>";
...
//UPDATE old orderId
$oldOrderId = $orderId;
// if orderId doesn't change, continue echo table content
} else {
echo "<table><tr><td>...</td></tr>";
}
// if the oldOrderId is not set, it means this is the first fetched row, and the very first table will be created
} else {
echo "<table><tr><th>...</th></tr>";
...
echo "<table><tr><td>...</td></tr>";
...
//SET oldOrderId
$oldOrderId = $orderId;
}
}
if ($i == $count) {
//End the last table
echo "</table><br>";
}
}
The code can run but will be buggy sometimes and I don't think this is a smart way to identify it. Is there any existed method like
$row = $stmt->fetch().prev()
to get the last row's orderId's value? Or if there's any better way to perform it?
Thanks!
The problem is your inclusion of GROUP BY orderId in your query. What this does is give you one row per each orderId in your table.
Since you are using SELECT *, then all you are getting back is one row for each orderId and one of the other values in the table for each of the other fields.
When using GROUP BY, you usually want to add a "group function" - like SUM(), COUNT(), GROUP_CONCAT(), etc. - to your query.
Your approach with the $oldOrderId is fine and could work if you change your query to something like:
SELECT * FROM orderTaken
WHERE orderStatus='10'
ORDER BY orderID DESC, orderTakenTime DESC

echo updated values instead of old values

How do I echo the latest values in column1? The below code echos the values before the update.
while($line = mysql_fetch_array($result)) {
$Student = $line["calss8"];
$querySf = "SELECT SUM(ABC) AS val1 FROM tbl1 WHERE student = '$Student'";
$resultSf = mysql_query($querySf);
$rSf = mysql_fetch_array($resultSf);
$totalSf = $rSf['val1'];
$totTMonth = $totalSf;
mysql_query("UPDATE tbl4 SET column1 = $totTMonth WHERE student = '$Student' LIMIT 1");
}
echo $line["column1"].",,";
As far as I know, you'll have to make a separate query to see what was just updated. I mean, run your select, perform your update, then do another select. You can get general information like how many rows were updated, but I don't think you can get specific information like the changed values in a column. Phil was right in suggesting that you should just print out the '$totTMonth' value since that is what you are updating your column with. That would be less overhead than doing another query to the database.
I think that problem starts before the code above. This code line will display the select results :echo $line["column1"].",,";. The variable $line is set before the code above. My solution is to do the following:
$result1 = mysql_query("SELECT column1 FROM student ..."); /* I insert the select query here */
While($row= mysql_fetch_array($result)) {
echo $row['column1'].",,";
}

Why is this PHP-MySQL code not working properly?

It was working before and maybe someone made changes to the code and I cant detect the problem after much debugging so hopefully someone can help.
I have an html form that lets a user choose a set of option and then on form submit, POSTS these options in an array which works perfectly fine. Then I am writing the elements of an array to a MySQL table and this is where the problem occurs. My code was working fine before but now its all weird. The outputs mix up for some reason.
Below is the array values passed and then the output below the arrays.
Here is my code that writes the array values to MySQL:
error_reporting(-1);
$arr=$_POST["itemsToAdd"];
$cal=$_POST["calendar"];
print_r($arr);
// Make a MySQL Connection
//empty table first to remove any previous old on-calls stored.
$query = "truncate table ProdOnCallSetup";
if(mysql_query($query)){
}
else{
}
foreach ($arr as &$value) {
// Insert a row of information into the table "ProdOnCallSetup"
mysql_query("INSERT INTO ProdOnCallSetup
(Email) VALUES('$value') ")
or die(mysql_error());
}
Here is the code giving the output or displaying the rows in MySQL:
<ol class=”list_style”>
<?php
//make MySQL connection
$query = "SELECT * FROM ProdOnCallSetup";
$result = mysql_query($query) or die(mysql_error());
while($row = mysql_fetch_array($result)){
echo "<li>".$row['Email']."</li>";
echo "<br />";
}
?>
</ol>
See the problem here? Even though I write them in the correct order in MySQL when I display them the order mixes up. Order is Justin, Achau, Chellatamby but when I echo is out from the DB its Achau, Chellatamby, Justin
Unless you specifically use an ORDER BY clause in your SELECT statement, the order in which rows are returned is indeterminate and may change.... it doesn't matter what order you added the records in, this is irrelevant... use ORDER BY...
SELECT * FROM ProdOnCallSetup ORDER BY Email
(or whatever column id you want to order them on)
If you want to order them in the order you added them to the database, you'll need an autoincrement column on the table, and order by that column

Using sql JOIN

I'm a sql noob trying to get this query to use 2 tables.
tables & columns are:
person:
department_id,
name,
etc...
department:
department_id,
dept_name,
etc...
I have a 'select' html form that the user will choose a dept_name from, and I need my php script to return every person with a matching department_id. Here is my code & query so far, I'd appeciate any help.
$search_dept = $_POST['search_dept'];
$conn = odbc_connect($odbc_name, $user_name, $pass_wd);
if ($conn) {
$query = "SELECT person.*
FROM department
JOIN person
ON department.department_id=person.department_id
WHERE department.name=$search_dept";
if($result = odbc_exec($conn, $query)) {
echo '..stuff';
while ($row = odbc_fetch_array($result)) {
...echo stuff
}
echo '...stuff';
}
else {
echo 'Query was unsuccessful';
}
}
else {
echo 'Unable to connect to database';
}
First of all, you are going about this the wrong way. You don't want to execute a WHERE clause against a text-type column if you can avoid it. Since your person table already has the department_id as a foreign key, you will want to use that value to do your selection. This means you will have to modify your select element to contain the department IDs as the options' values.
<!-- Example -->
<select name="dept_id">
<option value="1">Sales</option>
<option value="2">Support</option>
<option value="3">Fulfillment</option>
</select>
So now, not only will just the raw selection occur faster since you'll be executing against an indexed column (you did make it a proper FK so it's indexed, right?), but you will also be removing the join altogether! (which is another boost to the query's speed)
// Here is injection-safe code for the ODBC driver
$stmt = odbc_prepare( "SELECT * FROM person WHERE department_id = ?" );
$success = odbc_execute( $stmt, array( $_POST['dept_id'] ) );
// Here is the old, non-secure version, but is db-driver agnostic
$deptId = $_POST['dept_id']; // escape this please!
$query = "SELECT * FROM person WHERE department_id = $deptId";
Try this query, also make sure to escape any user input. What if the user would provide:
$_POST['search_dept']= "'; DROP TABLE person;";
Never ever ever thrust userinput!
$search_dept = mysql_escape_string($_POST['search_dept']); //make sure to escape this! you can use other functions for this as well. I'm not sure if PDO has some.
$query = "SELECT *
FROM person
JOIN department
ON department.department_id=person.department_id
WHERE department.name='$search_dept'";

Categories