prepared statements execute multiple queries at once - php

I have been trying this for hours and still no luck. Simply I am deleting rows from two tables using checkboxes. Let's assume I have checked two results and hit delete, then those two rows should be deleted from both tables.
In the below code the first query deletes two rows but the second one only deletes one row. If I just run each query separately then they both delete two rows? I have tried many times but I am not able to achieve what I wanted.
Can someone pleaseeee tell me why each query is failing to delete two rows? or is there a better way to do this? some kind of alternative?
$stmt1 = $mydb->prepare("DELETE from laptop where username = ? and id = ?");
echo $mydb->error;
foreach ($_POST['id'] as $id)
{
$stmt1->bind_param('ss', $username->username, $pdata);
$stmt1->execute();
}
$stmt2 = $mydb->prepare("DELETE from search where username = ? and id = ?");
echo $mydb->error;
foreach ($_POST['id'] as $id)
{
$stmt2->bind_param('ss', $username->username, $id);
$stmt2->execute();
}

Why not combine into one query?
$stmt1 = $mydb->prepare("DELETE from laptop, search where username = ? and id = ?");

In your example above the first query is looping over $_POST['id'], but it's always using the same value $pdata as the param for id=?.
If that query is deleting multiple rows, then you've got rows with duplicate username/id in that table. You should remove the loop, as you are doing extra work running the same delete query multiple times.
You mentioned that the first query was working and the second one wasn't though.
If that's the case, could you echo out the value of $id within your loop and verify that it is looping twice and the values are what you're expecting?

Related

Merge multiple foreach MySQL insert statements into one with PHP array data

I have a PHP array with different items and their respective values, and would need to update each row for each item in a database. Is there a way to only have one query to execute, instead of multiple foreach queries?
foreach($array as $key=>$item){
$image_id = $item['id'];
$order_id = $item['order_id'];
$sql = "UPDATE images SET order_id='$order_id' WHERE id='$image_id'";
$query = mysqli_query($connection, $sql);
} // end for each
You can't really combine it into one query using UPDATE, as the value and condition come in pairs (the value and condition is different for each row you are updating).
There is a hacky fix with INSERT INTO..ON DUPLICATE KEY UPDATE, but I would refrain from using that - see the question linked by RiggsFolly in the comments.
When using a prepared statement, you can execute the same query multiple times (you would have to query it multiple times anyways, even with mysqli_query(), but this is optimized and more secure when using a prepared statement).
$sql = "UPDATE images SET order_id=? WHERE id=?";
$stmt = $connection->prepare($sql);
foreach($array as $key=>$item){
$stmt->bind_param("ss", $item['order_id'], $item['id']);
$stmt->execute();
}
$stmt->close();
If your IDs are integers instead of strings, replace the respective s with an i.
PHP.net on mysqli::prepare()
PHP.net on mysqli-stmt::bind_param()
PHP.net on mysqli-stmt::execute()

elegant solution for multiple prepare statements

The problem I am trying to solve in a better way is to delete a folder with images that have tags. So for each image I need to delete
-the image itself
-tags of that image from three databases (img_offer, img_member, img_horses)
At the moment I get all image ids of the folder to be deleted and then iterate over these four times with the four different queries, which seems pretty inefficient.
The main problem is that as far as I know you can't have multiple prepare statements open at the same time and creating the statements new in each iteration seems also counter-intuitive.
What I think would be the best approach would be something like a multiple query prepare statement but I couldn't find anything similar so maybe someone here has an idea how to solve this in a cleaner way
My idea would be something like
$multiplePreparedStatement= "DELETE this FROM that WHERE id=?;
DELETE this2 FROM that2 WHERE id2=?;
DELETE this3 FROM that3 WHERE id3=?;";
$preparedStmt = $conn->prepare($multiplePreparedStatement);
foreach($imgArray as $imgId){
$preparedStmt->bind_param("iii", $imgId, $imgId, $imgId);
$preparedStmt->execute();
}
$preparedStmt->close();
But I don't think that would work as multiple SQL Queries are not supported in prepared statements or are they?
Here is my current code:
$id=$_GET['deleteAlbum'];
$getImages = "SELECT image_id AS id
FROM Images
WHERE folder_id = ?";
$deleteImage="DELETE FROM Images
WHERE image_id=?";
$deleteOffer = "DELETE FROM Images_Offers
WHERE image_id=?";
$deleteHorse = "DELETE FROM Images_Horses
WHERE image_id=?";
$deleteTeam = "DELETE FROM Images_Team
WHERE image_id=?";
//get all image ids
$ImgStmt=$conn->prepare($getImages);
$ImgStmt->bind_param("i", $id);
$ImgStmt->execute();
$ImgStmt->bind_result($id);
$imgToDelete = array();
while($ImgStmt->fetch()){
array_push($imgToDelete, $id);
}
$ImgStmt->close();
$stmt=$conn->prepare($deleteOffer);
foreach ($imgToDelete as $imgId){
$stmt->bind_param("i",$imgId);
$stmt->execute();
}
$stmt->close();
$stmt=$conn->prepare($deleteHorse);
foreach ($imgToDelete as $imgId){
$stmt->bind_param("i",$imgId);
$stmt->execute();
}
$stmt->close();
$stmt=$conn->prepare($deleteTeam);
foreach ($imgToDelete as $imgId){
$stmt->bind_param("i",$imgId);
$stmt->execute();
}
$stmt->close();
$stmt=$conn->prepare($deleteImage);
foreach($imgToDelete as $imgId){
unlink("../assets/img/images/img".$imgId.".jpg");
$stmt->bind_param("i",$imgId);
$stmt->execute();
}
$stmt->close();
I also had the idea of creating multiple connections but I think that might get problematic if e.g. delete an image while I still have a query iterating over images.
You do not have to iterate over image_id (at least not for the SQL data) at all. You can delete from the database everything associated with a particular folder_id in one go:
DELETE Images, Images_Offers, Images_Horses, Images_Team
FROM Images
LEFT JOIN Images_Offers ON Images_Offers.image_id = Images.image_id
LEFT JOIN Images_Horses ON Images_Horses.image_id = Images.image_id
LEFT JOIN Images_Team ON Images_Team.image_id = Images.image_id
WHERE folder_id = ?;
Of cause, before that you should unlink the actual files.

PHP Forloop loops through an array and insert current array item into sql database, only one record inserting

I have a script that gets data from a database, then loops through the results from the SELECT query by using a forloop and has a query that inserts the array data into another datbase. However only the first record gets inserted.
I get no errors
Here is the code.
//Get all from job
$getRecords = $connection->prepare("SELECT `CustomerFirstName`,`CustomerLastName`,`CASS_STD_LINE1`,`CASS_STD_LINE2`,`CASS_STD_CITY`,`CASS_STD_STATE`,`CASS_STD_ZIP`,`CustomerCounty`,`CustomerNumber`,`DealNumber`,`TradeIn_1_VIN`,`TradeIn_1_Make`,`TradeIn_1_Model`,`TradeIn_1_Year`,`FrontGross`,`BackGross`,`HoldBackAmount`,`VehicleYear`,`VehicleMake`,`VehicleModel`,`VehicleVIN`,`EntryDate`,`matched`,`notNew` FROM `auth` WHERE `matched` = ?");
$getRecords->execute(array($_POST['jobName']));
$gotRecords = $getRecords->fetchAll(PDO::FETCH_ASSOC);
$getRecords = null;
//Loop Through all records found with matching job name
for($i=0;$i<count($gotRecords); ++$i){
$rec = $remote->prepare("INSERT INTO `cob_matched_records`(first) VALUES (?)");
$rec->execute(array($gotRecords[$i]['CustomerFirstName']));
}
The problem with your script is most likely the line
$getRecords = null;
destroying the array before the code hits your for-loop.
(But that doesn't fit your description "However only the first record gets inserted.". Did you post the actual, unaltered code?)
The point (or one of the points) of prepared statements is that you prepare them once and then execute them multiple times with varying parameters. So, prepare the INSERT statement once before the loop and then execute it within with the current parameter(s):
// assuming PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION, otherwise error handling is missing....
// you might also be interested in http://docs.php.net/manual/en/pdo.begintransaction.php
$stmtSelect = $connection->prepare("SELECT `CustomerFirstName` FROM `auth` WHERE `matched` = ?");
$stmtInsert = $remote->prepare("INSERT INTO `cob_matched_records` (first) VALUES (?)");
$stmtSelect->execute( array($_POST['jobName']) );
foreach( $stmtSelect as $row ) {
$stmtInsert->execute( array($row['cob_matched_records']) );
}

PHP/MySQL query deleting data but not re-inserting

I have this PHP Code:
$stmt = $pdo_conn->prepare("DELETE from tickets_extra_emails where ticketnumber = :ticketnumber ");
$stmt->execute(array(':ticketnumber' => $ticket["ticketnumber"]));
$cc_contact_line = '';
foreach(explode("\n", $_POST["cc_contacts"]) as $cc_contact_line) {
//then insert new if its not blank
if(filter_var($cc_contact_line, FILTER_VALIDATE_EMAIL)) {
//see if it currently exists
$stmt = $pdo_conn->prepare("SELECT * from tickets_extra_emails where ticketnumber = :ticketnumber and email_address = :email_address ");
$stmt->execute(array(':ticketnumber' => $ticket["ticketnumber"], ':email_address' => $cc_contact_line));
$records = $stmt->fetchAll(PDO::FETCH_ASSOC);
if(count($records) == 0) {
echo 'insert '.$ticket["ticketnumber"].' - '.$cc_contact_line.'<br>';
$stmt = $pdo_conn->prepare("INSERT into tickets_extra_emails (ticketnumber, email_address) values (:ticketnumber, :email_address) ");
$stmt->execute(array(':ticketnumber' => $ticket["ticketnumber"], ':email_address' => $cc_contact_line));
}
}
}
that makes each line of a textarea a variable in a foreach loop.
if i put lines in the textarea and submit the form, it saves the data but then if there is already data in and i submit the form, it removes it.
what do i have wrong in my code? I have commented everything it does
Theres a significant difference between MySQL INSERT and UPDATE.
You will need to check against the database where you are inserting to and use a query to check if there is data existing in that row. Based on that query you can restructure your insert statement to be conditional and switch from an INSERT to an UPDATE.
Deleting existing data will not allow you to re-insert into the rows, the rows are existing and therefor require UPDATE. However if you are removing whole rows then you can indeed re insert the rows. I see this as not entirely efficient, when you can utilize the efficiency of UPDATE to its benefit here.
AFAIK, fetchAll will fail if there are 0 rows, so you won't be able to run a count on the records. Do you have errors enabled or logged?
I see what you are trying to do and why you want to delete then reinsert, although maybe not the best approach.
Update: Apparently rowCount() shouldn't be relied on for selects, so I think the best alternative is to change your select query to select a count. This will always return a value as long as the query is valid so you shouldn't have to worry about the fetch failing. As you noticed below, I just changed the SELECT * to a SELECT count(*) so this will count how many rows match your constraints. Then use fetchColumn() to select the first column of the first row (the count).
$stmt = $pdo_conn->prepare("SELECT count(*) from tickets_extra_emails where ticketnumber = :ticketnumber and email_address = :email_address ");
$stmt->execute(array(':ticketnumber' => $ticket["ticketnumber"], ':email_address' => $cc_contact_line));
$records = $stmt->fetchColumn();

What does this SQL statement do?

I am trying to understand this SQL statements :
$id = 5;
$stmt = $conn->prepare('SELECT * FROM myTable WHERE id = :id');
$stmt->execute(array('id' => $id));
while($row = $stmt->fetch()) {
print_r($row);
}
Can someone please explain me step by step what exactly is going on here?
From what i understand :
$stmt = $conn->prepare('SELECT * FROM myTable WHERE id = :id');
1) $stmt is about to take as iinput an SQL query. The SQL query is to select all the rows from a table that their id is equal to 5.
$stmt->execute(array('id' => $id));
2) We execute the statement. Now the $stmt has these rows?
$row = $stmt->fetch()
3) This is the most confusing line for me. What exactly happens here? Variable "row" takes one by one the rows that have id = 5 ? Is that what fetch() does ? And if yes , how exaxtly does it return the results? Its an array of all the correct answers? EG all the rows that have id = 5 ? I dont understand how exactly this while loop works here.The first time it runs "row" will have the first row ? The second time it runs , will have the second row that satisfies our creteria (id = 5) and so on? Is it like that every time i run fetch one result will be returned? And next time i run fetch , the next result , till there is no more result to satisfy the query?
I thing i am so close to get this one. Anything that could help me understand it completely would be highly appreciated !
I'll explain as comments:
$id = 5;
// Create a prepared statement - don't actually execute the statement yet.
// The :id value in the statement will be replaced by a parameter value (safely) when the
// statement is executed
$stmt = $conn->prepare('SELECT * FROM myTable WHERE id = :id');
// Execute the statement against the DB - the $stmt var now contains the result set for the
// executed statement. e.g. it contains *all* the results that the query fetched
$stmt->execute(array('id' => $id));
// Now we loop through the rows in the result set (they are all in memory at this point).
// "fetch" will start from row 1 and return the next result each time you call it again.
// when there are no more rows it returns FALSE and therefore breaks out of the while loop
while($row = $stmt->fetch()) {
print_r($row);
}
Just checking docs also and whilst this is how it was done previously (been years since I've touched PHP) it looks like stmt->fetch() actually places results into bound variables:
http://php.net/manual/en/mysqli-stmt.fetch.php
$row = array();
stmt_bind_assoc($stmt, $row);
// loop through all result rows
while ($stmt->fetch())
{
print_r($row);
}
Does the code you originally posted actually work? It doesn't appear you bind any variables and therefore since the $stmt-fetch() call returns bool TRUE/FALSE it would seem to be that $row would not get set to anything but TRUE/FALSE
here it uses PDO for execution,
Repeated SELECT using prepared statements through which you can call repeated query
$stmt = $conn->prepare('SELECT * FROM myTable WHERE id = :id');
it defines the prepared statement where :id is placeholder
$stmt->execute(array('id' => $id));
this places assigns the value to placeholder and execute the query
$row = $stmt->fetch()
it fetch the record from select
for more reference visit the link
http://www.php.net/manual/en/pdo.prepared-statements.php

Categories