Data loss using mysqli_data_seek - php

I run a query, and loop through it modifying one of the fields with the code below. I only need the modified number for a short time, and do not need it to go back to the database. This works correctly, and using the echos printed out the expected values.
while ($d1 = mysqli_fetch_array($d1_query))
{
echo "Before: " . $d1['d1_name'] . ": " . $d1['d1_earn_rate'] . "<br>";
if ( $e1['e_id'] == $h1['e_id'] )
$d1['d1_earn_rate'] = $d1['d1_earn_rate'] * 1.2;
echo "After: " . $d1['d1_name'] . ": " . $d1['d1_earn_rate'] . "<br><br>";
}
Afterwards, I want to calculate the total of a subset of the results. I use mysqli_data_seek to reset the counter to the first row, so I can loop through it. However, when I do, it calculates the total based on the original numbers in the query, not the revised ones.
I have used msqli_data_seek previously with no issues, but this is the first time I have modified data in the results before trying to loop back through it. I don't understand why I'm losing the data.
mysqli_data_seek($d1_query,0);
$counter = 0;
while ($counter < 15)
{
$counter++;
$d1 = mysqli_fetch_array($d1_query);
echo $d1['d1_name'] . ": " . $d1['d1_earn_rate'] . "<br>";
$total_earn_rate += $d1['d1_earn_rate'];
}

You appear to be thinking way too deep here. The matter is pretty simple:
the MySQL server holds a result set in its memory, the result of your previous query
mysqli_fetch_array pulls the data from the MySQL server into PHP's memory and returns it
you're assigning that fetched data to $d1
you're manipulating $d1
you reset MySQL's internal pointer of the result set and repeat the above process
At no point are you manipulating the result set that is held by the MySQL server, and you're always pulling data afresh from said MySQL result set via mysqli_fetch_array. Every time you call that function you'll get the unmodified data from the result set held by MySQL.

Related

Large result (500000 item) query ending before done looping through

I have a large result set returned in my query. For some reason, when I loop through the results, doing what I need with each row, I'm finding that the script is ending early.
$stmt1 = $mysqli1->prepare("select distinct p.tn, n.model, n.software_version , c.card_part_num
from N_DB.DSLAMS n
join N_DB.dslam_card on n.nodealias = c.nodealias
join N_DB.dslam_port p on c.index = p.dslam_card_index
WHERE ping_reply = '1'
order by p.tn
LIMIT 60000000");
//it's less than 60 million, but I set that limit to make sure my issue wasn't that I was setting the limit too low
if(!$stmt1->bind_result($num, $model, $software_version, $card))
{
echo "Binding results failed: (" . $stmt1->errno . ") " . $stmt1->error;
}
print "will query depo next \n";
if(!$stmt1->execute())
{
$tempErr = "Error querying depo db: " . $stmt1->error;
printf($tempErr . "\n"); //show mysql execute error if exists
$err->logThis($tempErr);
}
print "done querying depo \n";
$total_records = $stmt1->num_rows();
print "Total records to process: ".$total_records." \n"; //says 0, but it clearly has many
// when it loops thru them,
//printing things
print " Please wait. \n";
$count = 0;
while($stmt1->fetch()) {
$count ++;
if (($count % 50000) == 0){
print "Working on record ".$count." \n"; //I never see this before it prints done
}
//do other things that are more interesting
}//while
print "\n done looping through tn's "; //it gets to this too soon
I think I'm processing too many records, but there isn't a logical way to cut the results to be less than 500000, so the only solution is to divide up the results. I've been looking at taking forever, and limit..peppy comments. I'd like to divide up the results, but I'm having trouble understanding what these people are doing.
How would I divide up my results into chunks so I don't, presumably, run out of memory. I'm relatively new to MySQL, so I apologize if I'm a little green.
Oh, and I checked max_execution_time => 0 => 0 , so that looks fine.

php array find value and store in db and stop loop

I have an Array $column with two values: value and sum.
The array is ordered based on sum.
I want to store the first sum that is above 10 and stop the array so it is not storing the other values which are later in the array.
I tried different things including break; but this influences the rest of the script below it or is not working.
Does anyone know how to solve this?
<?php
foreach ($column as $value => $item) {
if ($item['sum'] >= 10) {
echo "First value above 10";
// store value in Database and stop string so next values won't go into DB
} else {
echo "lower than 10 and do nothing";
}
echo $item['value'] . " - " . $item['sum'] . " <br />";
}
?>
You are on the right track. If I understand you still need to keep looping even after the fact you have found your first value over ten. You just need to store a boolean flag in that case keeping track of the fact whether or not you already found one:
<?php
$itemFound = false;
foreach ($column as $value => $item) {
if (!itemFound && $item['sum'] >= 10) {
echo "First value above 10";
// query on connnection here
$itemFound = true;
}
echo $item['value'] . " - " . $item['sum'] . " <br />";
}
?>
If you need help with the database query, you are going to need to give more information about your local configuration.

While Loop Seems Endless

I have a table named getinvolved and in this table there are various fields and values, obviously. One such is named The Route and contains text separated by commas. For the sake of this we'll say they are Spot 1, Spot 2, Spot. Yes the spaces matter.
Now, in my code I first break this value up into an array based on the commas: $route = explode(",", $row['Content']); Content is the name of the row that contains the Spot 1, Spot 2, Spot text value. This all works fine, I have echo'd this and it appears perfectly.
Next comes the tricky bit, I have multiple other entries that are instead of being labelled The Route are instead labelled Route. This is an entry for each possible spot, while the current route is Spot 1, Spot 2, Spot it could always change to Spot 2, Spot 1, Tops.
Each possible entry has it's own row: Name, Type, Content. Type is where Route is set, Name is the name of the spot, and Content contains a Google Maps URL to show the spot in Google Maps Street View.
What I'm trying to do is take my array $route[] which currently contains Spot 1, Spot 2, Spot and check those values against all others. I've created a separate array $echoroute[] and this contains the actual route with all the information.
My code is as follows:
$sql = mysqli_query($link, "SELECT * FROM getinvolved WHERE Type='Route'");
$echoroute = array_fill(0,count($route),""); #Gives $echoroute[] 3 empty elements as $route will always contain 3 elements at the moment.
$i = 0;
$max = count($route);
if($sql)
{
foreach($route as $ii)
{
while($row = mysqli_fetch_assoc($sql))
{
if($row['Name'] == $ii)
{
$echoroute[$i] = "<a href='" . $row['Content'] . "' target='_blank'>" . $row['Name'] . "</a> --> ";
echo $i . " / " . $max . "<br />";
$i+=1;
if($i==($max)) {break 2;} else {break 1;}
}
}
}
}
I'm unable to figure out why but at present during running this code all that happens is it will go through the if as $sql passes, it enters the first and second while loops and then gets to the if($row['Name'] == $route[$i]) part. Here it seems to work fine until it actually enters the if statement (the value in $row['Name'] is equal to the one in $route[$i]).
$total is increased as where I ask it to echo it does, but only once. The code ends and displays the following:
0 / 3
3
The 1 represents the $total variable, which should go through 3 times according to while($total<$max).
The / is me adding a separator for ease of reading.
The 3 is the $max variable, or count($route), the total number of spots included in the $route array.
And finally the trailing 3 is a count() function of $echoroute letting me know there are 3 elements in that array.
Ultimately, my question is, why does $total never get to 2 and finish the loop as I would require?
This took a while to write, so I hope you understand I've put a bit of thought into this, I wrote this a while ago, and it needs some updating and this is where I am currently at.
EDIT:
Have narrowed this down now! Using several echo functions, it appears that the last run through starts, but only makes it as far as the while statement. It never actually enters the while statement. Currently I have two results echo'd and the last result just so happens to be at the bottom of the table. It's the last one to be used before the while($row = statement ends of it's own accord. Am I trapping the while statement or do I need to release it or something? I'm really confused and so close to having the final piece!
You initialize $echoroute with count($route) elements (3 in your example).
You loop over a condition and increase value of $i and $total if a condition is met.
At this point, into the while loop where $total and $i values are 2 ( while condition is met 2 < 3 ) and if they enter the if condition you get 3 value for $i and $total and if you echo $echoroute[$i] then you've got an error, because $echoroute is a 3 element array and you are pointing to a fourth element (remember array indices start from 0 ).
I think this is why you are not getting you expected output.
i'd write it this way, since there is chance (following Moor laws) that the loop on $total never ends
$sql = mysqli_query($link, "SELECT * FROM getinvolved WHERE Type='Route'");
$echoroute = array_fill(0,count($route),""); #Gives $echoroute[] 3 empty elements as $route will always contain 3 elements at the moment.
$i = 0;
$total = 0;
$max = count($route);
if($sql)
{
while($row = mysqli_fetch_assoc($sql))
{
if($row['Name'] == $route[$i])
{
$echoroute[$i] = "<a href='" . $row['Content'] . "' target='_blank'>" . $row['Name'] . "</a> --> ";
$i++;
$total++;
if ($total>$max) break;
echo $total . " / " . $max . "<br />" . $echoroute[$i] . count($echoroute);
}
}
}

While inside a while

I'm trying to count how many times a hashtag is mentioned in the database. So first while is getting all the hashtags, and the second is inside the other while to count how many times the hashtag is mentioned. But the problem is that the numbers isn't getting along correct, it is just showing 1,2,3,4,5.. etc, and when there is a hashtag mentioned two times it's showing i.e. 3+4.
How can I solve this?
$i = 0;
$popular_hashtags_query = mysql_query("SELECT * FROM " . $dbPrefix . "hashtags WHERE status=1");
while ($popular_hashtags = mysql_fetch_array($popular_hashtags_query)) {
echo "<div class='hashtag_label'><a data-hover='";
$count_hashtags_query = mysql_query("SELECT * FROM " . $dbPrefix . "hashtags WHERE status=1 AND hashtag='" . $popular_hashtags['hashtag'] . "'");
while ($count_hashtags = mysql_fetch_array($count_hashtags_query)) {
$i++;
echo $i;
}
echo "'><span>#".$popular_hashtags['hashtag'] . "</span></a></div>";
}
I suggest to use mysqli or PDO. in this case group by hashtag in the query is better way and not need to extra query and loop so.
$popular_hashtags_query = mysql_query("
SELECT
`hashtag`, count(*) AS `count`
FROM `" . $dbPrefix . "hashtags` WHERE `status` = 1 GROUP BY `hashtag`
");
while ($popular_hashtags = mysql_fetch_array($popular_hashtags_query)) {
echo "<div class='hashtag_label'><a data-hover='";
echo $popular_hashtags['count'];
echo "'><span>#" . $popular_hashtags['hashtag'] . "</span></a></div>";
}
There are a bunch of problems with your code. First, the mysql_ functions are deprecated and will eventually be removed from php entirely, so you should move over to mysqli_ functions or a PDO.
Second, your actions on $i are in the wrong place. You should be resetting $i = 0 as the first action inside the first loop, or else it's just going to count up the total number of times ANY hashtag is used.
Third, you're echoing $i inside the second while loop, which means every time the loop runs, you're going to be forever echoing increasing numbers. The echo should be outside the inner loop, after you've counted up the instances of the hashtag.
And finally, you can actually accomplish all of this with one loop by executing "SELECT hashtag, count(*) FROM " . $dbPrefix . "hashtags WHERE status=1 group by hashtag"
There's no need to loop over all records in a table to do the same thing again.
What you want is to use an aggregate function in you SQL query.
Something like the following:
SELECT hashtag, COUNT(hashtag)
FROM hashtags
GROUP BY hashtag

Displaying a multi-table mysql query

This is going to be really hard to explain but I'll attempt to do my best without confusing you all. I have the following table design;
Here is my mysqlFiddle to demonstrate the issue: http://sqlfiddle.com/#!2/1363c/1
As you can see, the tables work fine and the query is displaying what shelter has what service but my issue comes when I attempt to display this information on my web. I'm currently using the following code;
<?php
echo '<p>', "<strong>Shelter id</strong>: " . $query['shelter_id'].'</p>';
echo '<p>', "<strong>Shelter name</strong>: " . $query['shelter_name'].'</p>';
echo '<p>', "<strong>Street</strong>: " . $query['street'].'</p>';
echo '<p>', "<strong>City</strong>: " . $query['city'].'</p>';
echo '<p>', "<strong>Postcode</strong>: " . $query['postcode'].'</p>';
echo '<p>', "<strong>Contact Number</strong>: " . $query['phone_number'].'</p>';
echo '<p>', "<strong>Location</strong> : " . $query['location_name'].'</p>';
?>
but with the query I'm using, Its not going going to dupe all the information into one row it is, its going to create multiple row's for the service_name, I think.
Is it possible for me to create a query that will return all service's the shelter can do on one row?
Edit: Will i have to do 2 separate query's? One to get the generic shelter information and then another query to return the services into an array and then just run through them on the page?
how about using GROUP_CONCAT? What it does is it combines the values into comma separated value. And you can later use Explode() in PHP.
SELECT shelter_name,
GROUP_CONCAT(services.service_name) service_name
FROM shelter
INNER JOIN shelter_service
ON shelter.shelter_id= shelter_service.shelter_id
INNER JOIN services
ON shelter_service.service_id = services.service_id
GROUP BY shelter.shelter_id, shelter_name
ORDER BY shelter_name
SQLFiddle Demo
GROUP_CONCAT() use only if you have a limited number of rows (10-100), if the data is larger will slow your query a lot.
2 queries (one for types one for data)
keep this query and modify the result (my favorite way).
On server or JS loop trough your data and restructure it (add 1 extra dimension)
var new_data = {};
for(var i in data)//data is your $query
{
var row = data[i];
//create another layer of the array (make it in 2 dimensions)
if (typeof(new_data[row['Service_name']) == 'undefined)
new_data['Service_name'] = [];
//add only this kind of type data
new_data['Service_name'].push(data);
}
//now you can remove the data and use new_data
.4. Make sure the query is primarly sorted by Service name, and when you loop at display (echo) you show the current service name.
$current_name = '';
for(...)
//if we passed to a new service in the loop
if ($query['service_name'] != $current_name) {
echo '<h3>'.$query['service_name'].'</h3>;//display the new service
$current_name = $query['service_name'];
}

Categories