Array and for each loop issues - php

Code is below if I run one value in the array the results are correct if I run more than one value the results are of the price is incorrect its like it has messed around with the values somewhere ?? help appreciated
$dido=array('42204131','22204131');
foreach($dido as $did):
$query = "select * from dispatch,link where lid=dlid and did=$did";
$result = mysql_query($query) or die(mysql_error());
while($row = mysql_fetch_array($result)){
$vanc1=$row['vanc1'];
$vanc2=$row['vanc2'];
$vanc3=$row['vanc3'];
$vanc4=$row['vanc4'];
$vanc5=$row['vanc5'];
$anc1=$row['anc1'];
$anc2=$row['anc2'];
$anc3=$row['anc3'];
$anc4=$row['anc4'];
$anc5=$row['anc5'];
// price anc1
$querypanc1 = "select pprice from products where pid=$anc1";
$resultpanc1 = mysql_query($querypanc1);
while($row = mysql_fetch_array($resultpanc1))
{
$priceanc1=$row[pprice];
$tpriceanc1=$vanc1*$priceanc1;
}
// price anc2
$querypanc2 = "select pprice from products where pid=$anc2";
$resultpanc2 = mysql_query($querypanc2);
while($row = mysql_fetch_array($resultpanc2))
{
$priceanc2=$row[pprice];
$tpriceanc2=$vanc2*$priceanc2;
}
// price anc3
$querypanc3 = "select pprice from products where pid=$anc3";
$resultpanc3 = mysql_query($querypanc3);
while($row = mysql_fetch_array($resultpanc3))
{
$priceanc3=$row[pprice];
$tpriceanc3=$vanc3*$priceanc3;
}
// price anc4
$querypanc4 = "select pprice from products where pid=$anc4";
$resultpanc4 = mysql_query($querypanc4);
while($row = mysql_fetch_array($resultpanc4))
{
$priceanc4=$row[pprice];
$tpriceanc4=$vanc4*$priceanc4;
}
// price anc5
$querypanc5 = "select pprice from products where pid=$anc5";
$resultpanc5 = mysql_query($querypanc5);
while($row = mysql_fetch_array($resultpanc5))
{
$priceanc5=$row[pprice];
$tpriceanc5=$vanc5*$priceanc5;
}
$gtprice=$tpriceanc1+$tpriceanc2+$tpriceanc3+$tpriceanc4+$tpriceanc5;
$qrygt="UPDATE dispatch SET gtprice=$gtprice WHERE did=$did";
$resultgt=#mysql_query($qrygt);
}
endforeach;

1) The only possible issue I could spot in your code, is that when some of your select pprice from products where pid ... queries do not return any data, you retain value of $tpriceancX from previous iteration.
2) Also (out of topic) you can replace your 5 blocks of repeated code with for loop.
$gtprice = 0;
for ($i = 1; $i <= 5; $i++)
{
$querypanc = "select pprice from products where pid=".$row["anc$i"];
$resultpanc = mysql_query($querypanc);
while($pancrow = mysql_fetch_array($resultpanc))
{
$priceanc=$pancrow[pprice];
$tpriceanc=$row["vanc$i"]*$priceanc;
$gtprice += $tpriceanc;
}
}

Your first and biggest problem is the copy-pasta nature of your code. Let's try and break down what you're doing:
Setting up a list of ids
Running a query on those ids
Putting the results into an array
Running a separate query on each of those results
You are also using some very janky syntax. (ie foreach($foo as $bar):).
Break these things down into methods. What is a method? It takes an input and transforms it into an output.
//returns an array of price information
public function getPrices($idArray) { //note the good method and parameter names!
//do stuff
}
Now that we know what we are doing, we can start to fill in the implementation details:
public function getPrices($idArray) {
foreach($idArray as $id) {
//somehow get the gross-scale information
//then put it in a data object
//then call a function to get specific information
}
}
What should that sub-method do? Lets look at your current code snippet:
// price anc1
$querypanc1 = "select pprice from products where pid=$anc1";//sets up sql query
$resultpanc1 = mysql_query($querypanc1); //runs the query
while($row = mysql_fetch_array($resultpanc1)) { //for each result
$priceanc1=$row[pprice]; //gets the price
$tpriceanc1=$vanc1*$priceanc1; //calculates some other price
}
Those last two lines really suggest an object but maybe that's too heavyweight for your purpose. The first two lines are boiler plate you repeat endlessly. Lets write a function!
public function getPrices($name, $pid, $multiplier) {
$sqlQuery = "SELECT pprice FROM products WHERE pid=$pid";
$result = mysql_query($sqlQuery);
$prices = array();
while ($row = mysql_fetch_array($result) {
$key = "price".$name;//$key will be something like 'priceanc1'
$prices[$key] = $row[pprice];
$tkey = "tprice".$name;
$prices[$tkey] = $prices[$key] * $multiplier;
}
}
Now, this function is a bit unclean because it tries to do two things at once (queries the database and then massages the data into a usable array) but I wanted it to resemble what you were doing. With this function written we can go back to our higher level function an call it:
public function getPrices($idArray) {
foreach($idArray as $id) {
$sqlQuery = "SELECT * from dispatch, link WHERE lid=dlid and did=$id";
$prices = array();
while ($row = mysql_fetch_array($result) {
for ($idx = 1; $idx <= 5; $idx++) {
$name = "anc".$idx;
$pid = $row[$name];
$multiplier = $row["vanc".$idx];
$priceArray = getPrices($name, $pid, $multiplier);
$prices = array_merge($prices, $priceArray);
}
}
}
//put a var_dump here to check to see if you're getting good results!
return $prices;//Should be the aggregated prices you've gotten from the db
}
Now, that is what you're attempting to do, but I admit I don't understand how your database is set up or what your variables actually mean. Pressing on! We also note that unnecessary massaging of data falls away.
You can call this like so:
$ids = array();
$ids[] = 42204131;
$ids[] = 22204131;
$prices = getPrices($ids);
var_dump($prices);//shows the result of your work
Now that you have the prices, you can pass them to another function to run the update:
updatePrices($prices);
I'll let you write that part on your own. But remember; break down what you're doing and have repeated elements be handled by the same function. The real lesson to learn here is that programming is really communicating: your code doesn't communicate anything because there is so much repeated noise. Use good variable names. Tighten what you're doing down to functions with single tasks. This way anyone reading your code (including you!) will know what you're trying to do and where you've gone wrong.

Related

How to save query in multidimesional array?

I have this script executing as a cron job everyday to update days remaining to pay invoices. I first query every row of my table and attempt to store the data in a multidimensional array but this seems to be storing everything I query in the first element of my array.
Here's my script:
<?php
include '../inc/dbinfo.inc';
ini_set("log_errors", 1);
ini_set("error_log", "/tmp/php-error.log");
error_log( "################################################# UpdateVendorInvoiceDays.php #################################################" );
$three = 3;
$fetchAllInvoices = "SELECT VENDORINVOICEID, VdrInvoiceReceived, PaymentDue, COUNT(*), DATEDIFF(PaymentDue, NOW()) FROM tblVendorInvoices WHERE VdrInvoiceStatusID != ?";
$getInvoices = $conn->prepare($fetchAllInvoices);
$getInvoices->bind_param("i", $three);
$getInvoices->execute();
$result = $getInvoices->get_result();
$rows = array();
$j = 0;
while($row = $result->fetch_assoc())
{
$rows[$j][] = $row;
$j++;
}
echo json_encode($rows[0][0]); //Only outputs one row
//UPDATE DAYS REMAINING IN EACH ENTRY THAT ISNT PAID
$updateDaysRemaining = "UPDATE tblVendorInvoices SET DaysRemaining = ? WHERE VENDORINVOICEID = ? AND VdrInvoiceStatusID ! = ?";
$setDays = $conn->prepare($updateDaysRemaining);
$k = 0; //incrementor
$numberOfEntries = $rows['COUNT(*)'];
for($k;$k<$numberOfEntries;$k++){
$setDays->bind_param("iii", $rows[$k]["DATEDIFF(PaymentDue, NOW())"],
$rows[$k]['VENDORINVOICEID'], $three);
if($setDays->execute()){
error_log('Cron success');
}else{
error_log('Cron fail');
}
}
?>
Currently the output from my first query is:
[[{"VENDORINVOICEID":88,"VdrInvoiceReceived":"2018-08-21","PaymentDue":"2018-07-27","COUNT(*)":2,"DATEDIFF(PaymentDue, NOW())":-25}]]
and my error log only gives me a notice for $rows['COUNT(*)'] being undefined (which makes sense)
I've looked at other answers here but they don't seem to have the same structure as I do.
EDIT: I also have 2 rows in my database but this only puts out one. I forgot to mention this.
There are a couple of simplifications to get all of the rows. Instead of...
while($row = $result->fetch_assoc())
{
$rows[$j][] = $row;
$j++;
}
echo json_encode($rows[0][0]);
You can just return all rows using fetch_all()...
$rows = $result->fetch_all (MYSQLI_ASSOC);
echo json_encode($rows);
Then encode the whole array and not just the one element - which is what $rows[0][0] was showing you.
As for you other problem - change in your select statement to
COUNT(*) as rowCount
and then you can use this alias for the field reference...
$rows['COUNT(*)']
becomes
$rows['rowCount']

PHP: Fastest way to loop through a array / stringbuiler or something else

We have a PHP script that loops through many XML / CSV files from different websites. Right now we manage to build a good XML / CSV parser script.
The PHP script we wrote is looping though some BIG XML or CSV files. In these XML or CVS files contains Barcodes from different products.
Right now before the script starts I fill an array with the Product ID + Barcode from the MySQL like this:
function Barcodes_Array() {
$sql = "SELECT ProductId, Barcode FROM Products WHERE (Barcode <> '') ";
$res = mysql_query($sql);
while ($rijen = mysql_fetch_assoc($res)) {
$GLOBALS['arrBarcodes'][] = $rijen;
}
}
Each time we loop through the XML (or CSV) files we have to check if the Barcode exists in the array and return the Product ID.
For searching in the function:
$ProductId = SearchBarcodeProduct($EanNr, 'Barcode');
And yet the function:
function SearchBarcodeProduct($elem, $field)
{
$top = sizeof($GLOBALS['arrBarcodes']) - 1;
$bottom = 0;
$ProductId = 0;
while($bottom <= $top)
{
if($GLOBALS['arrBarcodes'][$bottom][$field] == $elem) {
return $GLOBALS['arrBarcodes'][$bottom]['ProductId'];
}
else {
if (is_array($GLOBALS['arrBarcodes'][$bottom][$field])) {
if (in_multiarray($elem, ($GLOBALS['arrBarcodes'][$bottom][$field]))) {
return $GLOBALS['arrBarcodes'][$bottom]['ProductId'];
}
}
}
$bottom++;
}
return $ProductId;
}
We fill in the array because it took forever each time we ask the MySQL Products Table.
My Question is now:
It still takes a VERY long time each time looping through the array of the barcodes. Is there a faster way for any other solutions maybe a different way then a array?
Can someone help please i am working like weeks on this stupid :) thing!
Why do you need 2 functions?
Try just one
function itemBarcode($id) {
$id = intval($id);
$sql = "SELECT ProductId, Barcode FROM Products WHERE ProductId = $id Barcode <> '') ";
$res = mysql_query($sql);
if ($row = mysql_fetch_assoc($res)) {
return $row['barcode'];
} else {
return 0;
}
}
Update if you need to search by barcode you can create another function:
function itemProduct($barcode) {
$sql = "SELECT ProductId, Barcode FROM Products WHERE Barcode = $barcode ";
$res = mysql_query($sql);
if ($row = mysql_fetch_assoc($res)) {
return $row['ProductId'];
} else {
return 0;
}
}
Sounds like you are missing an index on your Barcode column in your database.. A single row lookup using a presumably unique single indexed column should be blisteringly fast.
CREATE INDEX Barcode_Index ON Products (Barcode)
Then simply:
SELECT ProductId FROM Products WHERE Barcode = *INPUT*
You could also make the index UNIQUE if you NULL the Barcode where they currently = '' if there are more than one of these.
Another option is keying the array you have with the Barcode:
while ($rijen = mysql_fetch_assoc($res)) {
$GLOBALS['arrBarcodes'][$rijen['Barcode']] = $rijen;
}
or even just:
while ($rijen = mysql_fetch_assoc($res)) {
$GLOBALS['arrBarcodes'][$rijen['Barcode']] = $rijen['ProductId'];
}
Then you can do a straight look up:
$ProductId = isset($GLOBALS['arrBarcodes'][$Barcode])
?$GLOBALS['arrBarcodes'][$Barcode]['ProductId']
:0;
or:
$ProductId = isset($GLOBALS['arrBarcodes'][$Barcode])
?$GLOBALS['arrBarcodes'][$Barcode]
:0;
N.B Please read the warnings in the comments about use of $GLOBALS and mysql_query.
If you need it, store the barcodes array in an object or variable instead.
PDO is pretty handy, and I think it can also key your returned array for you on fetch.

Performance, check if value exists array or query

I need to check if a value exists in my database
I have a table where every user has an unique code. For example: 5h27f.
These values and users add up very quickly. So very soon I might have +2000 unique codes. What's the best, fastest and most efficient way to check if a value is unique?
foreach ($users as $user) {
$is_unique = FALSE;
while ($is_unique == FALSE) {
$code = unique_code();
$query = "SELECT * FROM unique_code_table WHERE code='$code';";
$res = $mysqli->query($query);
if ($res->num_rows > 0 {
} else {
$is_unique = TRUE;
}
}
}
OR
$query = "SELECT code FROM unique_code_table;";
$res = mysqli->query($query);
$codes = array();
$i = 0;
while ($row = $res->fetch_object()) {
$codes[$i] = $row->code;
$i++;
}
$code = unique_code();
while (in_array($code, $codes) {
$code = unique_code();
}
(this code might not be 100% accurate, I've written this just to explain the purpose of the question.)
I'd say that one query trip to the database vs. potentially 2000+ is significantly better to do. Second script will be significantly faster.
On the first code a LIMIT 1 would do wonders but compared to the second query it will pale as far as benchmarks are concerned.
Put the following at the bottom of your script to fine tune and benchmark:
PHP 5.4 +
$sParseTime = microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"];
echo $sParseTime;

php sql find and insert in empty slot

I have a game script thing set up, and when it creates a new character I want it to find an empty address for that players house.
The two relevant table fields it inserts are 'city' and 'number'. The 'city' is a random number out of 10, and the 'number' can be 1-250.
What it needs to do though is make sure there's not already an entry with the 2 random numbers it finds in the 'HOUSES' table, and if there is, then change the numbers. Repeat until it finds an 'address' not in use, then insert it.
I have a method set up to do this, but I know it's shoddy- there's probably some more logical and easier way. Any ideas?
UPDATE
Here's my current code:
$found = 0;
while ($found == 0) {
$num = (rand()%250)+1; $city = (rand()%10)+1;
$sql_result2 = mysql_query("SELECT * FROM houses WHERE city='$city' AND number='$num'", $db);
if (mysql_num_rows($sql_result2) == 0) { $found = 1; }
}
You can either do this in PHP as you do or by using a MySQL trigger.
If you stick to the PHP way, then instead of generating a number every time, do something like this
$found = 0;
$cityarr = array();
$numberarr = array();
//create the cityarr
for($i=1; $i<=10;$i++)
$cityarr[] = i;
//create the numberarr
for($i=1; $i<=250;$i++)
$numberarr[] = i;
//shuffle the arrays
shuffle($cityarr);
shuffle($numberarr);
//iterate until you find n unused one
foreach($cityarr as $city) {
foreach($numberarr as $num) {
$sql_result2 = mysql_query("SELECT * FROM houses
WHERE city='$city' AND number='$num'", $db);
if (mysql_num_rows($sql_result2) == 0) {
$found = 1;
break;
}
}
if($found) break;
}
this way you don't check the same value more than once, and you still check randomly.
But you should really consider fetching all your records before the loops, so you only have one query. That would also increase the performance a lot.
like
$taken = array();
for($i=1; $i<=10;$i++)
$taken[i] = array();
$records = mysql_query("SELECT * FROM houses", $db);
while($rec = mysql_fetch_assoc($records)) {
$taken[$rec['city']][] = $rec['number'];
}
for($i=1; $i<=10;$i++)
$cityarr[] = i;
for($i=1; $i<=250;$i++)
$numberarr[] = i;
foreach($cityarr as $city) {
foreach($numberarr as $num) {
if(in_array($num, $taken[]) {
$cityNotTaken = $city;
$numberNotTaken = $number;
$found = 1;
break;
}
}
if($found) break;
}
echo 'City ' . $cityNotTaken . ' number ' . $numberNotTaken . ' is not taken!';
I would go with this method :-)
Doing it the way you say can cause problems when there is only a couple (or even 1 left). It could take ages for the script to find an empty house.
What I recommend doing is insert all 2500 records in the database (combo 1-10 with 1-250) and mark with it if it's empty or not (or create a combo table with user <> house) and match it on that.
With MySQL you can select a random entry from the database witch is empty within no-time!
Because it's only 2500 records, you can do ORDER BY RAND() LIMIT 1 to get a random row. I don't recommend this when you have much more records.

Stumped in the middle of a PHP loop

Here's what I've got so far-
$awards_sql_1 = mysql_query('SELECT * FROM categories WHERE section_id = 1') or die(mysql_error());
$awards_sql_2 = mysql_query('SELECT * FROM categories WHERE section_id = 2') or die(mysql_error());
$awards_sql_3 = mysql_query('SELECT * FROM categories WHERE section_id = 3') or die(mysql_error());
$awards_sql_4 = mysql_query('SELECT * FROM categories WHERE section_id = 4') or die(mysql_error());
$loop = 1;
while($row_sections = mysql_fetch_array($sections_query)) {
$category = 1;
echo "<h3>" . $row_sections['section_name'] . " (Loop# $loop)</h3>";
while($categories = mysql_fetch_array(${"awards_sql_{$loop}"})) {
${"winners_sql_{$loop}"} = mysql_query("SELECT * FROM 2009_RKR_bestof WHERE section = $loop && category = $category ORDER BY result_level ASC") or die(mysql_error());
echo "<h4><strong>{$categories['category_name']}</strong></h4>";
echo "<ul class=\"winners\">";
>> while($winners = mysql_fetch_array(${"winners_sql_{$loop}"})) {
switch ($winners['result_level']) {
case 1: $result_level = "Platinum"; break;
case 2: $result_level = "Gold"; break;
case 3: $result_level = "Silver"; break;
}
if (isset($winners['url'])) { $anchor = ""; $close = ""; }
echo "<li>$anchor{$winners['winner']}$close ($result_level)</li>";
unset($anchor);
unset($close);
}
echo "</ul>";
$category++;
}
$loop++;
}
Where I'm getting stumped, is I'm getting this thing to loop through correctly, my loop counter ($loop) is working, but when it gets time to spit out the actual reward recipients after the first loop through winners, it's only producing the category titles, the list-items are not getting looped out.
I added a little pointer to where I think the problem begins or centers around (>>).
My guess is I need to maybe unset a var somewhere, but I don't know, I can't see it.
I'm with KM - you're displaying a single page and with your loops, you've got a LOT of queries happening at once - what if 1,000 people hit that page at the same time? ouch...
Maybe consider a larger query (with some repeated data) and loop through it once?
For example:
SELECT
section_name,
category_name,
result_level,
url,
winner
FROM 2009_RKR_bestof
INNER JOIN categories ON 2009_RKR_bestof.category = categories.id
INNER JOIN sections ON 2009_RKR_bestof.section = sections.id
ORDER BY section_name,category_name ASC
In your loop, you can do checks to determine if you're in a new section (category/whatever):
//pseudo-code
$current_section = "";
while($stuff = mysql_fetch_array($sql))
{
if ($current_section == "")
{
$current_section = $stuff["section_name"];
}
if ($current_section == $stuff["section_name"])
{
//keep going in your loop
}
else
{
//we've gotten to a new section - so close your html and start a new section
}
}
You get the idea..
My guess would be that it is a data problem. It isn't having trouble reading the titles, only the winners. If it iterated once, I would check the data, and ensure that winners_sql_2 - winnders_sql_4 are getting actual data. Perhaps add an echo winners_sql_2 line, to output the contents of the query, and ensure the query is framed correctly.

Categories