How to stop second foreach from looping more than once - php

I have an query which select all ids from a table. Once I have all id's, they are stored in an array which I foreach over.
Then there is an second array which pull data from url (around 5k rows) and should update DB based on the id's.
The problem - second foreach is looping once for each ID, which is not what I want. What I want is to loop once for all id's.
Here is the code I have so far
$query = " SELECT id, code FROM `countries` WHERE type = 1";
$result = $DB->query($query);
$url = "https://api.gov/v2/data?api_key=xxxxx";
$api_responce = file_get_contents($url);
$api_responce = json_decode($api_responce);
$data_array = $api_responce->data;
$rows = Array();
while($row = $DB->fetch_object($result)) $rows[] = $row;
foreach ($rows as $row) {
foreach ($data_array as $key => $dataArr) {
$query = "UPDATE table SET data_field = $dataArr->value WHERE country_id = $row->id LIMIT 1";
}
}
The query returns 200 id's and because of than the second foreach (foreach ($data_array as $key => $dataArr) { ... }) execute everything 200 times.
It must execute once for all 200 id's not 200 * 5000 times.

Since the question is aboot using a loop, we will talk about the loop, instead of trying to find another way. Actually, I see no reason to find another way.
->Loops and recursions are great, powerful tools. As usually, with great tools, you need to also find ways of controlling them.
See cars for example, they have breaks.
The solution is not to be slow and sit to horses era, but to have good brakes.
->In the same spirit, all you need to master the power called recursions and loops is to stop them properly. You can use if cases and "break" command in PHP.
For example, here we have a case of arrays containing arrays, each first child of the array having the last of the other (1,2,3), (3,4,5) and we want to controll the loop in a way of showing data in a proper way (1,2,3,4,5).
We will use an if case and a counter :
<?php
$array = array( array(-1,0,1), array(1,2,3,4,5), array(5,6,7,8,9,10), array(10,11,12,13,14,15) );
static $key_counter;
foreach( $array as $key ){
$key_counter = 0;
foreach( $key as $key2 ){
if ( $key_counter != 0 ) {
echo $key2 . ', ';
}
$key_counter = $key_counter + 1;
}
}
Since I dont have access to your DB is actually hard for me to run and debbug the code, so the best I can say is that you need to use an if case which checks if the ID of the object is the ID we want to proccess, then proceed to proccessing.
P.S. Static variables are usefull for loops and specially for recurrsions, since they dont get deleted from the memory once the functions execution ends.
The static keyword is also used to declare variables in a function
which keep their value after the function has ended.

Related

How do I insert values into an multidimensional-array, then show them?

I'm fairly new to php, and I don't know how to work with arrays very well. Here's the deal, I want to add into a multidimensional array three or more values I obtain from my database, then I want to sort them based on the timestamp (one of the values). After that, I want to show all of the sorted values. I can't seem to do this, here's the code
$queryWaitingPatients = 'SELECT ArrivalTime, TargetTime, Order, Classification FROM exams WHERE (CurrentState = "Pending")';
$results = mysql_query($queryWaitingPatients) or die(mysql_error());
if (mysql_num_rows($results) == 0) {
echo '<p>There\'s currently no patient on the waiting list.</p>';
return;
}
while ($rows = mysql_fetch_array($results)) {
extract($rows);
//now is the part that I don't know, putting the values into an array
}
// I'm also not sure how to sort this according to my $TargetTime
asort($sortedTimes);
//the other part I don't know, showing the values,
Thanks for the help!
Well, let's look at your code. First, you have a query that's returning a result set. I don't recommend using mysql_fetch_array because it's not only deprecated (use mysqli functions instead) but it tends to lend itself to bad code. It's hard to figure out what you're referencing when all your keys are numbers. So I recommend mysqli_fetch_assoc (be sure you're fully switched to the mysqli functions first, like mysql_connect and mysqli_query)
Second, I really dislike using extract. We need to work with the array directly. Here's how we do this
$myarray = array();
while ($rows = mysqlI_fetch_assoc($results)) {
$myarray[] = $rows;
}
echo $myarray[0]['ArrivalTime'];
So let's go over this. First, we're building an array of arrays. So we initialize our overall array. Then we want to push the rows onto this array. That's what $myarray[] does. Finally, the array we're pushing is associative, meaning all the keys of the row match up with the field names of your query.
Now, the sorting really needs to be done in your query. So let's tweak your query
$queryWaitingPatients = 'SELECT ArrivalTime, TargetTime, `Order`, Classification
FROM exams
WHERE CurrentState = "Pending"
ORDER BY TargetTime';
This way, when your PHP runs, your database now churns them out in the correct order for your array. No sorting code needed.
$arr = array();
while ($rows = mysql_fetch_array($results)) {
array_push ($arr, $row);
}
print_r($arr);
<?php
$queryWaitingPatients = ' SELECT ArrivalTime, TargetTime, Order, Classification, CurrentState
FROM exams
WHERE CurrentState = "Pending"
ORDER BY TargetTime ';
$results = mysql_query($queryWaitingPatients) or die(mysql_error());
if ($results -> num_rows < 1)
{
echo '<p>There\'s currently no patient on the waiting list.</p>';
}
else
{
while ($rows = mysqli_fetch_array($results))
{
$arrivaltime = $row['ArrivalTime'];
$targettime = $row['targettime'];
$order = $row['Order'];
$classification = $row['Classification'];
echo "Arrival: ".$arrivaltime."--Target time: ".$targettime."--Order: ".$order."--Classification: ".$classification;
}
}
echo "Done!";
//or you could put it in a json array and pass it to client side.
?>

PDO - Foreach with Array Respect

using PDO, I receive 1+ rows and turn them into an array like this:
while($row = $car_sales->fetch(PDO::FETCH_ASSOC)){
$car_id_array[] = $row["car_id"];
$car_type_array[] = $row["car_type"];
$dealer_id_array[] = $row["dealer_id"];
$buyer_id_array[] = $row["seller_id"];
}
I'm trying to simply "mix" each level of the array to act as a unit and go down the foreach loop together, submitting the $q query in order. In other words, something like this:
foreach($dealer_id_array as $dealer_id) {
if ($car_type=='new') {
if ($dealer_id==$buyer_id){
$q = 'UPDATE car_sales SET new_cars=new_cars+1 WHERE dealer_id=:dealer_id';
} else if ($dealer_id!=$buyer_id){
$q = 'UPDATE car_sales SET new_cars=new_cars-1 WHERE dealer_id=:dealer_id';
} else if ($car_type=='old') {
if ($dealer_id==$buyer_id){
$q = 'UPDATE car_sales SET old_cars=old_cars+1 WHERE dealer_id=:dealer_id';
} else if ($dealer_id!=$buyer_id){
$q = 'UPDATE car_sales SET old_cars=old_cars-1 WHERE dealer_id=:dealer_id';
}
$car_update = $dbhandle->prepare($q);
$car_update->execute(array(':dealer_id' => $dealer_id));
}
The loop should run with the first array values if there is only one value retrieved from the while loop. If there are more, the foreach should run as many times as there are dealer_ids from the while loop, while respecting the order. This example won't work, but I'm looking for possible solutions to solve this issue correctly. What do you think would be the most efficient way to do this?
I might be misunderstanding you, but I believe if you just replaced your foreach loop with a for loop, and counted one of the arrays you would solve your issue:
for($i = 0; $i < count($dealer_id_array); $i++) {
and then simply using $i to access the correct item in your arrays:
$car_type_array[$i];
But having said that, I don't really see the point of the initial four arrays in the first place. Could you not just directly execute the code inside the foreach loop straight inside the while loop in the first place?
EDITED: to fix code example

i was wondering how to handle a MySQL request in php as an Object?

I was wondering how I can handle a mysql request in php precisely as an object.
Ex:
//supposing...
$beginning=$_GET['start'];//value equal to 3
$ending=$_GET['end'];//value equal to 17
$conn=new mysqli("localhost","user","password","databasename");
$query=$conn->query("select name, favoriteFood, weight, from tablename");
1- Supposing that tablename has 23 rows, how to printing only 14 rows, beginning for example by 3rd row and ending in 17th row, as following?
Ex:
//supposing... It, I guess, should result in error but is a sketch of my ideia
for($i=$beginning,$colsCol=$query->fetch_array(MYSQLI_ASSOC); $i<$ending; $i++)
printf("%s %s %s<\br>",$colsCol['name'][$i],$colsCol['favoriteFood'][$i],$colsCol['weight'][$i]);
2 - And later, how to order the resulted rows with $query variable?
P.S.: I know that to get results ordered, I could user order by columname, but in this case I would like to order the resulted rows after query been done.
If you want to sort later, after the query's done, then you'd need to store the results in a PHP data structure and do the sorting there. Or re-run the query with new sorting options.
As for fetching only certain rows, it'd be far more efficient to retrieve only the rows you want. Otherwise (for large result sets) you're forcing a lot of data to be pulled off disk, sent over the wire, etc... only to get thrown away. Rather wasteful.
However, if you insist on doing things this way:
$row = 0; $data = array();
while($row = $query->fetch_array(MYSQLI_ASSOC)) {
$row++;
if (($row < 3) || ($row > 17)) {
continue;
}
$data[] = $row;
}
for 2D array you can use it.
function asort2d($records, $field, $reverse=false) {
// Sort an array of arrays with text keys, like a 2d array from a table query:
$hash = array();
foreach($records as $key => $record) {
$hash[$record[$field].$key] = $record;
}
($reverse)? krsort($hash) : ksort($hash);
$records = array();
foreach($hash as $record) {
$records []= $record;
}
return $records;
} // end function asort2d
Use SQL for SQL-tasks:
"how to printing only 14 rows, begging for example by 3rd row and ending in 17th row"
$stmt = $database->prepare('SELECT `name`, `favoriteFood`, `weight` FROM `tablename` LIMIT :from, :count');
$stmt->bindValue(':from', (int)$_GET['start'] - 1);
$stmt->bindValue(':count', (int)$_GET['end'] - (int)$_GET['start']);

Working with arrays in Kohana, Blank page?

tl;dr - Pushing an array (by $array[] or $array[$id] is not working in Kohana 3, it gives a blank white page.
I'm using Kohana (3), it's my first experience with MVC and it's been great so far; however, I'm working with a database and encountered a weird problem that I was hoping someone could shed some light on:
My workflow is like this, to give you an idea of my problems surrounding:
$sql = "SELECT table1.row1, max(table2.row1) as `maxAwesome` FROM table1, table2 WHERE table1.id=table2.table1id GROUP BY table1.id";
$table1Results = DB::query(Database::SELECT, $sql)->execute();
$masterArray = array();
foreach ($table1Results as $result1)
{
$sql = "SELECT * FROM table2 WHERE table2id='" . $result1['id'] . "' AND column > 21";
$table2Results = DB::query(Database::SELECT, $sql)->execute();
$subArray = array();
foreach ($table2Results as $result2)
{
$subArray[$result1['id']] = $result2;
// Even had just $subArray[] = array("whatever");
}
$masterArray[] = array("table1Data" => array(), "table2Data"=> $subArray);
}
I do a query where I run a couple max/min functions then do a query within the foreach doing another select to build a master array of data formatted the way I want it and all the SQL etc works fine and dandy; however, the problem arises when I'm pushing the array.
It seems whenever I push the array by doing either $array[] = array("data"); or by specifying the key $array[$id] = array("data"); Kohana gives me a straight blank page, no error, no output etc.
Sometimes I get a Kohana error indicating the key does not exist (duh, I'm creating it) but for the most part the output is straight white.
Why is this happening? Am I going about it wrong?
Thanks in advance.
Clarity edit:
My SQL blunders aside, the issue lies in the building of the secondary array, for example:
$queryStores = "SELECT stores.store_id, stores.title, max(product.discount) as `max_discount`, min(product.discount) as `min_discount`
FROM stores, products
WHERE products.store=stores.store_id
GROUP BY products.store";
$stores = DB::Query(Database::SELECT, $queryStores)->execute();
$formattedStores = array();
if (count($stores))
{
foreach ($stores as $store)
{
$formattedStores[$store['store_id']] = array(
"title" => $store['title'],
);
// Same result if just doing $formattedStores[] = array();
// Problem goes away should I do:
// $formattedStores = array("This works");
//
}
}
echo "<pre>";
print_r($formattedStores);
echo "</pre>";
That does not print an array, it simply gives a blank page; however, if i change it to just re-set the $formattedStores array to something I get an output. What is it about pushing the array that's causing a problem, perhaps a Kohana bug?
Thanks
Your code should be like:-
$sql = "SELECT table1.id, table1.row1, max(table2.row1) as `maxAwesome`
FROM table1, table2
WHERE table1.id = table2.table1id
GROUP BY table1.id";
$table1Results = DB::query(Database::SELECT, $sql)->execute();
$masterArray = array();
if (count($table1Results))
{
foreach ($table1Results as $result1)
{
$sqlInner = "SELECT * FROM table2
WHERE table2id = '" . $result1['id'] . "'
AND column > 21";
$table2Results = DB::query(Database::SELECT, $sqlInner)->execute();
$subArray = array();
if (count($table2Results))
{
foreach ($table2Results as $result2)
{
$subArray[$result1['id']] = $result2;
// Even had just $subArray[] = array("whatever");
}
}
$masterArray[] = array("table1Data" => array(), "table2Data"=> $subArray);
}
}
Some valuable coding standards & miss-ups:-
You have got the "id" field (w.r.t. the "table1" DB table) missing from the first SQL.
The second SQL should be better written using another variable naming, so as to keep it separate from the first one. Hence the second variable is named as "$sqlInner".
It's always better to check for any existence of array elements in an array variable, so I have used the simple checks using the "if" statement.
Hope it helps.
I've determined this to be memory related.

PHP Sorting associative-array by other array

I need to sort an associative-array in the exact order of the content of another array.
The Arrays are retrieve by 2 separate sql-requests (stated below). The requests could not be combined to only one request, so I have to sort the second array into the order of the first one.
These are the arrays:
#Array which contains the id's in needed order
$sorting_array = array(1,2,3,8,5,6,7,9,11,10...);
#Array which contains the values for the id's, but in order of "id" ASC
$array_to_sort = array(
array("id" => "1", "name" => "text1", "help" => "helptxt2");
array("id" => "2", "name" => "text2", "help" => "helptxt2");
);
The SQL-Queries:
SQL-Ouery for $sorting_array: (the db-field 'conf' is setup as "text", maybe this is my problem so that I have to first explode and implode the entries before I could use it for the next query.)
$result = sql_query("select conf from config where user='me'", $dbi);
$conf = sql_fetch_array($result, $dbi);
$temp = explode(',', $conf[0]);
$new = array($temp[0], $temp[1], $temp[2], $temp[3],$temp[4],
$temp[5], $temp[6], $temp[7], $temp[8], $temp[9],
$temp[10], ...);#Array has max 30 entries, so I count them down here
$sorting_array = implode(',', $new);
SQL-Ouery for $array_to_sort:
$result = sql_query("SELECT id, name, helptxt
FROM table
WHERE id IN ($sorting_array)
AND language='english'");
while ($array_to_sort[] = mysql_fetch_array ($result, MYSQL_ASSOC)) {}
array_pop($array_to_sort);#deleting the last null entry
I could access $array_to_sort as follows to see the content one by one:
(if the lines below don't match the array above, than I mixed it up. However, the lines below is what brings the content)
echo $array_to_sort[0]["id"];
echo $array_to_sort[0]["name"];
echo $array_to_sort[0]["helptxt"];
But it is sorted by "id" ASC, but I need exactly the sorting as in $sorting_array.
I tried some things with:
while(list(,$array_to_sort) = each($sorting_array)){
$i++;
echo $array_to_sort . "<br>";
}
which only brings the Id's in the correct order, but not the content. Now I'm a bit confused, as I tried so many things, but all ended up in giving me the same results.
Maybe the sql-query could be done in one step, but I didn't brought it to work.
All results to my searches just showed how to sort ASC or DESC, but not what I want.
Furthermore I must confess that I'm relative new to PHP and MySQL.
Hopefully some one of you all could bring me back on track.
Many thanks in advance.
To fetch your results:
$result = mysql_query("SELECT id, name, helptxt
FROM table
WHERE id IN ($sorting_array)
AND language='english'");
$array_to_sort = array();
while ( ($row = mysql_fetch_assoc($result)) !== false ) {
// associate the row array with its id
$array_to_sort[ $row[ "id" ] ] = $row;
}
To display them in order of $sorting_array:
foreach ( $sorting_array as $id ) {
// replace the print_r with your display code here
print_r( $array_to_sort[ $id ] );
}
And a bonus tip for the code fetching $sorting_array:
$result = mysql_query("select conf from config where user='me'", $dbi);
$conf = mysql_fetch_array($result, $dbi);
$temp = explode(',', $conf[0]);
// limit to 30 ids
$new = array();
// no need to do this manually, use a loop
for ( $i = 0; $i < 30; ++$i )
$new[] = $temp[ 0 ];
$sorting_array = implode(',', $new);
Its a little hard to tell because there is a lot going on here, in the future you'll probably get better/more responses if you ask several simple questions and figure out yourself how to make the answers fit together.
Your best bet long term is going to be to restructure your SQL tablessuch that you can combine these query together. You can do what you're asking in PHP, but it's going to be slower than doing it in MySQL and much more complicated.
To do what you're asking (pretty slow in PHP):
$sorted = array();
foreach ( $sorting_array as $id )
{
foreach ( $array_to_sort as $values )
{
if ( $values['id'] == $id )
{
$sorted[] = $values;
break;
}
}
}
what I tend to do in such a situation is first to rearrange the array with the data. so the keys represent ids
In your case:
$array_to_sort_ids = array();
foreach ($array_to_sor as $item)
{
$array_to_sort_ids[$item['id']] = $item;
}
Then sorting is as simple as:
$array_sorted = array();
foreach ($sorting_array as $id)
{
$array_sorted[] = $array_to_sort_ids[$id];
}
This solution is quite efficient, since you only have 2 foreach loops.
EDIT!!!
As I couldn't edit my question anymore, I just like to state my solution this way:
The tip to rethink my database was what brought me to some testings and then I found the solution, with the following query:
$result = sql_query("SELECT id, name, helptxt
FROM table
WHERE id IN ($sorting_array)
AND language='english'
ORDER BY FIELD(id,$sorting_array)");
while ($array_to_sort[] = mysql_fetch_array ($result, MYSQL_ASSOC)) {}
array_pop($array_to_sort);#deleting the last null entry
Just the line:
ORDER BY FIELD(id,$sorting_array)
will do the trick. It orders the results the way you want, even if this means 1,4,2,3,9,7,...
Sometimes it's so easy, when you know where to look.
Thanks again!!!

Categories