Optimising a foreach loop write to MYSQL - php

I have a table of data where I update multiple rows in one transaction. The Foreach loop below works perfectly, however if the table contains a large number of rows there is a fair delay, presumably while the whole table is worked through line by line.
Even if I only change one field in one line, there is a significant delay (20 seconds), which again I am assuming is because the loop is working through each line.
//get data from form
$id2 = $_POST['id2'];
$status2 = $_POST['status2'];
$comment = $_POST['comments2'];
foreach ($id2 as $key2 => $value2){
$query3 = "UPDATE newthing SET comments='$comment[$key2]' WHERE id = $value2 ";
$query4 = "UPDATE newthing SET status='$status2[$key2]' WHERE id = $value2 ";
//execute query
mysql_query($query3);
mysql_query($query4);
}
Is there a more efficient way of undertaking this task? I am open to learning as required if there is a java / ajax / any other sort of tool to use. Additionally, I am aware that mysql_query is old now, so if there's a PDO method of doing this, so much the better. I haven't got my head around PDO at all yet :-/
Many thanks,
Jason

Start by merging into a single update:
foreach ($id2 as $key2 => $value2){
$query3 = "UPDATE newthing SET comments='$comment[$key2]', status='$status2[$key2]' WHERE id = $value2 ";
//execute query
mysql_query($query3);
}
Then start learning about prepared statements/bind variables with the MySQLi or PDO extensions to replace the deprecated MySQL extension, and to help prevent SQL injection

Related

Update multiple rows with single query using MySQL and PHP

<?php
$userData = array();
while (anything to create a loop) {
$value1 = $result1_from_loop;
$value2 = $result2_from_loop;
$value3 = $result3_from_loop;
$userData[] = '("'.$value1.'", "'.$value2.'", "'.$value3.'")';
} // THIS ENDS THE WHLE OR FOR LOOP
$query = 'INSERT INTO users (data1,data2,data3) VALUES' . implode(',', $userData);
mysql_query($query);
?>
The above code works perfectly for inserting multiple records into table users as seen above and it's very fast as well.
However, I am trying to use the same method to update after going through a loop as before. I have no idea how to achieve this.
I want something like this:
<?php
$userData = array();
while (Loop statement) {
$value1 = $result1_from_loop;
$value2 = $result2_from_loop;
$value3 = $result3_from_loop;
$userData[] = '("'.$value1.'", "'.$value2.'", "'.$value3.'")';
} // This ends the WHLE or FOR loop
$query = 'UPDATE users SET(data1,data2,data3) VALUES' . implode(',',$userData) WHERE data2=$value2
mysql_query($query);
I know the above code is not close to correct, syntax is even wrong. I just pasted it to show the idea of what I want achieved. In the WHERE statement how will data2 get to know the value of each $value2?
UPDATE uses a different format to INSERT. For UPDATE, your code should look something like this:
$query = 'UPDATE users SET data1 = $userData[0], data2 = $userData[1], data3 = $userData[2] WHERE data2=$value2';
Although just as a note, using mysql_query is not advised as it is deprecated (and will be removed altogether in later PHP versions) and your code is vulnerable to SQL injection. At a minimum I'd recommend using mysqli_query instead and looking into using prepared statements.

update array data to database inside looping

I face a problem with update more then one value with the same name to database.
//while loop
{
<input name="exists[]" value='$row1[Status_Name]'></input>
}
bellow are how I update the data to database
if (isset($_POST["updsts"]))
{
$gid = $_POST["id"];
$sqlq = "SELECT * FROM orderstatus WHERE Status_Group = '$gid'";
$result = mysqli_query($conn, $sqlq);
$rowcount = mysqli_num_rows($result);
if ($rowcount == 0)
echo "No records found";
else
{
$x = '0';
while( $x<$rowcount)
{
$stsname = $_POST["exists[$x]"];
$sqlu = "UPDATE orderstatus SET
Status_Name = '$stsname'
WHERE Status_Group = '$gid'";
$x++;
}
}
My $row1[Status_Name] will show all the status_name inside a table.
You can loop over the post array key:
foreach ($_POST['exists'] as $val) {
// Do your updates here
}
Additionally, this code has a lot of other serious problems you should be aware of.
You're not escaping any data used in the context of HTML. Use htmlspecialchars() around any arbitrary data you're concatenating into HTML. Without this, you risk creating invalid HTML as well as potential security issues with injected scripts.
You're not escaping any data used in your queries! As it stands right now, pretty much anyone can do whatever they want with your database data. Automated bots hit these sort of scripts and exploit them all the time. Use parameterized queries, always. Never concatenate data into the context of a query!
There's no need for this select and then update loop. Just use one update.

Seemingly identical sql queries in php, but one inserts an extra row

I generate the below query in two ways, but use the same function to insert into the database:
INSERT INTO person VALUES('','john', 'smith','new york', 'NY', '123456');
The below method results in CORRECT inserts, with no extra blank row in the sql database
foreach($_POST as $item)
$statement .= "'$item', ";
$size = count($statement);
$statement = substr($statement, 0, $size-3);
$statement .= ");";
The code below should be generating an identical query to the one above (they echo identically), but when I use it, an extra blank row (with an id) is inserted into the database, after the correct row with data. so two rows are inserted each time.
$mytest = "INSERT INTO person VALUES('','$_POST[name]', '$_POST[address]','$_POST[city]', '$_POST[state]', '$_POST[zip]');";
Because I need to run validations on posted items from the form, and need to do some manipulations before storing it into the database, I need to be able to use the second query method.
I can't understand how the two could be different. I'm using the exact same functions to connect and insert into the database, so the problem can't be there.
below is my insert function for reference:
function do_insertion($query) {
$db = get_db_connection();
if(!($result = mysqli_query($db, $query))) {
#die('SQL ERROR: '. mysqli_error($db));
write_error_page(mysqli_error($db));
} #end if
}
Thank you for any insite/help on this.
Using your $_POST directly in your query is opening you up to a lot of bad things, it's just bad practice. You should at least do something to clean your data before going to your database.
The $_POST variable often times can contain additional values depending on the browser, form submit. Have you tried doing a null/empty check in your foreach?
!~ Pseudo Code DO NOT USE IN PRODUCTION ~!
foreach($_POST as $item)
{
if(isset($item) && $item != "")
{
$statement .= "'$item', ";
$size = count($statement);
$statement = substr($statement, 0, $size-3);
$statement .= ");";
}
}
Please read #tadman's comment about using bind_param and protecting yourself against SQL injection. For the sake of answering your question it's likely your $_POST contains empty data that is being put into your query and resulting in the added row.
as #yycdev stated, you are in risk of SQL injection. Start by reading this and rewrite your code by proper use of protecting your database. SQL injection is not fun and will produce many bugs.

SQL statement inside loop with PHP, good idea?

I ran into the following question while writing a PHP script. I need to store the first two integers from an array of variable lenght into a database table, remove them and repeat this until the array is empty. I could do it with a while loop, but I read that you should avoid writing SQL statements inside a loop because of the performance hit.
A simpliefied example:
while(count($array) > 0){
if ($sql = $db_connect->prepare("INSERT INTO table (number1, number2) VALUES (?,?)")){
$sql->bind_param('ii',$array[0],$array[1]);
$sql->execute();
$sql->close();
}
array_shift($array);
array_shift($array);
}
Is this the best way, and if not, what's a better approach?
You can do something like this, which is way faster aswell:
Psuedo code:
$stack = array();
while(count($array) > 0){
array_push($stack, "(" . $array[0] . ", " . $array[1] . ")");
array_shift($array);
array_shift($array);
}
if ($sql = $db_connect->prepare("INSERT INTO table (number1, number2)
VALUES " . implode(',', $stack))){
$sql->execute();
$sql->close();
}
The only issue here is that it's not a "MySQL Safe" insert, you will need to fix that!
This will generate and Array that holds the values. Within 1 query it will insert all values at once, where you need less MySQL time.
Whether you run them one by one or in an array, an INSERT statement is not going to make a noticeable performance hit, from my experience.
The database connection is only opened once, so it is not a huge issue. I guess if you are doing some insane amount of queries, it could be.
I think as long as your loop condition is safe ( will break in time ) and you got something from it .. it's ok
You would be better off writing a bulk insert statement, less hits on mysql
$sql = "INSERT INTO table(number1, number2) VALUES";
$params = array();
foreach( $array as $item ) {
$sql .= "(?,?),\n";
$params[] = $item;
}
$sql = rtrim( $sql, ",\n" ) . ';';
$sql = $db_connect->prepare( $sql );
foreach( $params as $param ) {
$sql->bind_param( 'ii', $param[ 0 ], $param[ 1 ] );
}
$sql->execute();
$sql->close();
In ColdFusion you can put your loop inside the query instead of the other way around. I'm not a php programmer but my general belief is that most things that can be done in language a can also be done in language b. This code shows the concept. You should be able to figure out a php version.
<cfquery>
insert into mytable
(field1, field2)
select null, null
from SomeSmallTable
where 1=2
<cfloop from="1' to="#arrayLen(myArray)#" index="i">
select <cfqueryparam value="myArray[i][1]
, <cfqueryparam value="myArray[i][]
from SomeSmallTable
</cfloop>
</cfquery>
When I've looked at this approach myself, I've found it to be faster than query inside loop with oracle and sql server. I found it to be slower with redbrick.
There is a limitation with this approach. Sql server has a maximum number of parameters it will accept and a maximum query length. Other db engines might as well, I've just not discovered them yet.

Mysql_query UPDATE

I could swear that I had this working last week, but now I get errors.
In PHP I have a large CSV file that I run through a foreach loop and in this loop I have a created a variable that adds an UPDATE line to itself, like this:
foreach ($csv->data as $value){
$updater .= "UPDATE tblProduktData SET xtra = 2 WHERE id = '$value[1]';";
}
mysql_query("$updater") or die(mysql_error());
The CSV file contains over 3000 lines so having the mysql_query() inside the loop obviously makes the process slow and is not recommendable.
Can anyone tell me if I'm missing something or just doing it wrong?
We will temporarily ignore the fact that you are using a PHP extension mysql_ that has been deprecated ( Scheduled for removal from the language) for a number of years now.
For some reason you are adding to the sql query each time through the loop by using the .= syntax. I assume you thought you could run more than one query at a time using the mysql_ extension, but you cannot.
So try this :-
foreach ($csv->data as $value){
$updater = "UPDATE tblProduktData SET xtra = 2 WHERE id = '$value[1]'";
mysql_query($updater) or die(mysql_error());
}
This is in fact a perfect candidate for using mysqli_ or PDO prepared statements.
The mysqli_ extension manual
The PDO manual
Try this:
$id = "0"; // initialze the ids to update with a non-existing value
// fetch all the ids into a variable
foreach ($csv->data as $value){
$id .= "," . $value[1]
}
$updater .= "UPDATE tblProduktData SET xtra = 2 WHERE id in (".$id.") ;";
mysql_query("$updater") or die(mysql_error());

Categories