PHP process MySQL query row-by-row - php

I have combined a PHP script to count words in MySQL textfield and update another field accordingly.
It works well with relatively small tables - but when I tried with really big table (10M records) - of course I've got "PHP Fatal error: Allowed memory size of 134217728 bytes exhausted"
Could somebody hint how to modify the script below to process the data "row-by-row" ?
<?php
$con1 = mysqli_connect('localhost','USERNAME','PASSWORD','DATABASE');
if (!$con1) {
die('Could not connect: ' . mysqli_error($con1));
}
$sql = "SELECT id FROM TableName";
$result = mysqli_query($con1, $sql);
while ($row = mysqli_fetch_assoc($result)) {
$to = $row["id"];
$sql1 = "SELECT textfield FROM TableName WHERE id = '$to' ";
$result1 = mysqli_query($con1,$sql1);
$row1 = mysqli_fetch_assoc($result1);
$words=(str_word_count($row1['textfield'],0));
$sql2="UPDATE TableName SET wordcount = '$words' WHERE id ='$to'";
$result2 = mysqli_query($con1,$sql2);
}
mysqli_close($con1);
?>

MySQL queries have the clause limit o, n, so you can run
SELECT id FROM TableName limit 0, 10
for example to get only 10 elements from the start. Now, the first number is the offset (the index where you start your work from) and the second is the number of elements you would expect to get. Now, these are the ideas you need to know in order to have success in doing this:
you will need to write a loop
in the loop you will always get n elements (n could be 1 as you wanted, or more)
in each step you increment o by n, so the new offset will be starting where the results ended previously
you can ensure an order, like order by id, for example
you can wrap the loop we are speaking about here around most of your code

Related

How to count the amount of same results in column?

I've developed a database, where i have three sets of columns:
- Username
- Feeling
- Remark
The entry's for feelings are all the same, because they're being selected from a dropdown menu. I'm looking for a way to count the amount of same results and then echo it on a site with PHP, but I can't get any further than this:
<?php
$con=mysqli_connect("localhost","username","password", "database");
if (mysqli_connect_errno()) {
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
$query = "SELECT COUNT(*) FROM thefeels WHERE feeling = 'Happy'";
$result = mysqli_query($con, $query);
var_dump($result)
?>
In this code I want to count the amount of times happy occurs in a column, but even that is not working. How can I count the amount of times the same results is in a column?
So if Happy is there four times and Sad two times it should display:
Happy: 4
Sad: 2
This is a basic Counting Rows task. You will find some examples in the official documentation.
In your case it would be:
$query = "SELECT feeling, COUNT(*) as count FROM thefeels GROUP BY feeling";
$result = mysqli_query($con, $query);
Now you can use the "old school" way (which you will find in many totorials):
while ($row = mysqli_fetch_assoc($result)) {
echo "{$row['feeling']}: {$row['count']}<br>";
}
or move forward and separate data fetching from data processing and data output with:
$feelingCounts = $con->fetch_all(MYSQLI_ASSOC);
And do what ever you need with the fetched data. For example:
var_dump($feelingCounts);
Use conditional aggregation:
SELECT COUNT(CASE WHEN feeling = 'Happy' THEN 1 END) as Happy,
COUNT(CASE WHEN feeling = 'Sad' THEN 1 END) as Sad
FROM thefeels

PHP - Exceeding allowed memory when processing large dataset

I have a list data with 999,000 records.
I have a select query and a while loop to get the data, I use array_push to add the retrieved value in loop into one array.
And then I want it so every loop processes 1000 values in this array.
My problem is when use array_push with big data I get the error:
Fatal Error: Allowed Memory Size of 134217728 Bytes
How can I optimize my code to resolve my problem?
My code is below:
$sql = "select customer_id";
$sql .= " from";
$sql .= " t_customer t1";
$sql .= " inner join t_mail_address t2 using(mid, customer_id)";
$result = $conn->query($sql);
$customerArray = array();
while ($row = $result ->fetch(PDO::FETCH_ASSOC)) {
array_push($customerArray , $row);
}
// Execute every 1000 record
foreach(array_chunk($customerArray , 1000) as $execCustomerArray ) {
// My code to execute for every records.
// ....
}
I'm unsure if it would fix anything, but one thing I will say is, your use of pushing all records into an array is silly.
You're using fetch to fetch them one by one, then adding them all to an array, why on earth aren't you just using PDOStatement::fetchAll() ?
Example:
$sql = "select customer_id";
$sql .= " from";
$sql .= " t_customer t1";
$sql .= " inner join t_mail_address t2 using(mid, customer_id)";
$result = $conn->query($sql);
$customerArray = $result->fetchAll(PDO::FETCH_ASSOC);
// Execute every 1000 record
foreach(array_chunk($customerArray , 1000) as $execCustomerArray ) {
// My code to execute for every records.
// ....
}
This may not fix your memory issue, because we can't see what the heavy lifting is for every customer record, but I will say that while loop you had was silly but most likely not the cause of your memory issue
Depending on if this is a script, or a web page thing, you could also have an incremental loop sort of thing, and use the MySQL LIMIT function to implement basic paging for your data, thus preventing it from coming into memory all at once,

Display the amount of Paid items in my database using php

I am using php and mysql to create a page that displays all of the jobs we have in the database. The data is shown is a table and when a row is clicked a modal window triggers with the information of the clicked job inside. At the top of the page I want a simple counter that shows amount of paid jobs, invoiced jobs etc etc. I am using the code below but having no luck...
<?php
$con = mysql_connect("localhost","databaseusername","password");
if (!$con) {
die('Could not connect: ' . mysql_error());
}
mysql_select_db("databasename", $con);
$result = mysql_query("select count(1) FROM jobslist");
$row = mysql_fetch_array($result);
$total = $row[0];
mysql_close($con);
?>
This code as far as I am aware is counting the amount of INT columns set to 1 rather than 0. No matter what I try I can't seem to get it to count the amount of 'paid' items in the database or 'invoiced' etc etc.
Once the count function is complete currently I am echoing out the outcome as below:
<?php echo "" . $total;?>
I am sure I am overlooking something simple, but any help is appreciated.
EDIT: TABLE STRUCTURE INCLUDED
http://i.stack.imgur.com/hcMJV.png
Assuming a column called paid you could restructure the query similar to the following. If you needed to sum the amounts involved that requires additional tweaking.
$result = mysql_query("select
( select count(*) from `jobslist` where `paid`=1 ) as 'paid',
( select count(*) from `jobslist` where `paid`=0 ) as 'unpaid'
from jobslist");
$rows = mysql_num_rows( $result );
while( $rs=mysql_fetch_object( $result ) ){
$paid=$rs->paid;
$unpaid=$rs->unpaid;
echo 'Total: '.$rows.'Paid: '. $paid.' Unpaid: '.$unpaid;
}
When I do this I usually name the COUNT result. Try this out:
$result = mysql_query("SELECT COUNT(*) AS total_rows FROM jobslist;");
$row = mysql_fetch_array($result);
$total = $row['total_rows'];
If you do not want to name the COUNT result, then give the following a go:
$result = mysql_query("SELECT COUNT(*) FROM jobslist;");
$row = mysql_fetch_array($result);
$total = $row['COUNT(*)'];
select count(1) FROM jobslist
This code as far as I am aware is counting the amount of INT columns set to 1 rather than 0.
No, this is just counting rows in your table and not filtering. If you want to count something with a specific filter you have to add that filter condition:
SELECT COUNT(*) AS `MyCount`
FROM `joblist`
WHERE `MyColumn` = 1; -- assuming MyColumn contains the INT you're looking for
You should stop using mysql_* functions. These extensions have been removed in PHP 7. Learn about prepared statements for PDO and MySQLi and consider using PDO, it's really pretty easy.
First you should change deprecated mysql_... to mysqli_... (look here how to). But it's not the reason you fail.
Unlike you seem to suppose, COUNT(1) will not look for an INT column having value 1.
Instead you must use COUNT(*) or COUNT(a_column_name) (same result), with adding a WHERE clause stating which condition is involved.
Here you seem wanting to count records where a given column (say the_column) has value 1. So you should:
SELECT COUNT(*)
FROM jobslist
WHERE the_column = 1
Last point: you don't need echo "" . in <?php echo "" . $total;?>.
Merely write <?php echo $total;?>.

SQL to only fetch some rows?

It was some time ago I worked with PHP, MySQL and SQL, so I need some help. In my table I have 44 rows, but I only want to get 24 of them. Before I have just loaded all the rows like in the code below, and now I need some help to modify it to only load 24 rows. Thanks!
$query = "SELECT * FROM {$tableObject} {$sort1};";
$res = $mysqli->query($query);
$row_cnt = mysqli_num_rows($res);
while($row01 = $res->fetch_object()) {
// Some other code here
}
Use this in your query:
LIMIT 24
LIMIT is a MySQL function that selects a particular range of results from your query results. There are basically two ways of using it:
By simply specifying the number of results you want to fetch, like LIMIT 24; or
By specifying another range in the form of LIMIT X, Y. Where X is the beginning and Y is number of rows you want to fetch, like: LIMIT 10,5 that would select the 5 results from row 11 to 15
In your particular case you can simply replace this line:
$query = "SELECT * FROM {$tableObject} {$sort1};";
For:
$query = "SELECT * FROM {$tableObject} {$sort1} LIMIT 24;";
or even:
$query = "SELECT * FROM {$tableObject} {$sort1} LIMIT 0,24;";
For a better understanding about how to use limit, I recommend you to read this page from MySQL manual

show 2 random rows instead of one

MY SQL QUERY:
$q = mysql_query("SELECT * FROM `ads` WHERE keywords LIKE '%$key%' ORDER BY RAND()");
RESULTS: KEYWORD123
This query searches and results in one random row but i want to show 2 random rows.
How to do that?
any solution?
how??
im grabbing it using this
$row = mysql_fetch_array($q); if ($row
<= 0){ echo 'Not found'; }else{ echo
$row['tab']; }
That query (as-is) will return more than one row (assuming more than one row is LIKE %$key%). If you're only seeing one record, it's possible you're not cycling through the result set, but rather pulling the top response off the stack in your PHP code.
To limit the response to 2 records, you would append LIMIT 2 onto the end of the query. Otherwise, you'll get every row that matches the LIKE operator.
//Build Our Query
$sql = sprintf("SELECT tab
FROM ads
WHERE keyword LIKE '%s'
ORDER BY RAND()
LIMIT 2", ('%'.$key.'%'));
// Load results of query up into a variable
$results = mysql_query($sql);
// Cycle through each returned record
while ( $row = mysql_fetch_array($result) ) {
// do something with $row
echo $row['tab'];
}
The while-loop will run once per returned row. Each time it runs, the $row array inside will represent the current record being accessed. The above example will echo the values stored in your tab field within your db-table.
Remove your order by and add a LIMIT 2
That happens after the execution of the SQL.
Right now you must be doing something like
$res = mysql_query($q);
$r = mysql_fetch_array($res);
echo $r['keywords'];
what you need to do
$q = mysql_query("SELECT * FROM ads WHERE keywords LIKE '%$key%' ORDER BY RAND() LIMIT 2");
$res = mysql_query($q);
while($r = mysql_fetch_array($res)){
echo "<br>" . $r['keywords'];
}
Hope that helps
This query will return all rows containing $key; if it returns only one now this is simply by accident.
You want to add a LIMIT clause to your query, cf http://dev.mysql.com/doc/refman/5.0/en/select.html
Btw both LIKE '%... and ORDER BY RAND() are performance killers

Categories