Yesterday i decided to learn PDO and rewrite our server php to PDO.
The thing that jumped to my mind while rewriting the code is the need of repeated use of bindParam for the same parameters i already used.
Here is an example:
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbh->beginTransaction();
$stmt = $dbh->prepare("INSERT INTO Products(productID,numOfLikes) VALUES (:productID,0) ON DUPLICATE KEY UPDATE productID = productID;");
$stmt->bindParam(":productID",$productID);
$stmt->execute();
if($customerID !== 0){
//*****Check, if customerID is in the Database, else add the customerID to the Database.
$stmt = $dbh->prepare("INSERT INTO Customers(customerID) VALUES (:customerID) ON DUPLICATE KEY UPDATE customerID = customerID;");
$stmt->bindParam(":customerID",$customerID);
$stmt->execute();
//*****if customerID and productID are NOT registered together ,then register and add +1 to productID numOfLikes
$stmt = $dbh->prepare("SELECT customerID, productID FROM CustomerProducts WHERE productID = :productID AND customerID = :customerID");
$stmt->bindParam(":productID",$productID);
$stmt->bindParam(":customerID",$customerID);
$stmt->execute();
if ($stmt->rowCount() == 0) {
//echo "added";
$stmt = $dbh->prepare("INSERT INTO CustomerProducts(customerID, productID) Values (:customerID,:productID)");
$stmt->bindParam(":customerID",$customerID);
$stmt->bindParam(":productID",$productID);
$stmt->execute();
$stmt = $dbh->prepare("UPDATE Products SET numOfLikes = numOfLikes + 1 WHERE productID = :productID");
$stmt->bindParam(":productID",$productID);
$stmt->execute();
}else {
//echo "removed";
$stmt = $dbh->prepare("DELETE FROM CustomerProducts WHERE productID = ".$productID." AND customerID = ".$customerID);
$stmt->bindParam(":customerID",$customerID);
$stmt->bindParam(":productID",$productID);
$stmt->execute();
$stmt = $dbh->prepare("UPDATE Products SET numOfLikes = numOfLikes - 1 WHERE productID = ".$productID);
$stmt->bindParam(":productID",$productID);
$stmt->execute();
}
}
$dbh->commit();
Is there a way to write it in "prettier way"?
Can you see any flows in that could. I would appreciate every help.
Note: this code will be for production use in the near future.
Yes there is...
You can supply bindParam as an array to the execute function...
Something like this:
$statement->execute([
':username'=> $username,
':password'=> $password
]);
It's using bindParam and execute in just one statement, and it looks cleaner in my opinion.
Yes, you can get around the repeated variables by defining mySql user variables like this:
$psVars = $dbh->prepare("SET #pid = :productID;");
$psVars->bindParam(':productID', $productID);
$psVars->execute();
Then, in subsequent statements, just use #pid instead of a bound parameter
Related
on my first UPDATE statement, im trying to have my WHERE value contain the variable $couponCode but it does not work as of now. This is so that the correct row updates depending on what the input is. any help would be appreciated.
if ($couponCode == $coupons_db3['coupon_code']){
echo $couponCode;
$stmt = $db->prepare('UPDATE promocode_3 SET used = 1 WHERE coupon_code ='.$couponCode);
$stmt = $db->prepare('UPDATE usr_customer_profile SET packageid = 3 WHERE usrcustomerid = :usrcustomerid');
$stmt->bindValue(':usrcustomerid', $_SESSION['usrcustomerid'], PDO::PARAM_INT);
$stmt->execute();
break;
}
You need to bind the couponCode as well.
if ($couponCode == $coupons_db3['coupon_code']){
echo $couponCode;
$stmt = $db->prepare('UPDATE promocode_3 SET used = 1 WHERE coupon_code =:couponCode');
$stmt->bindValue(':couponCode', $couponCode, PDO::PARAM_STR);
$stmt->execute();
$stmt = $db->prepare('UPDATE usr_customer_profile SET packageid = 3 WHERE usrcustomerid = :usrcustomerid');
$stmt->bindValue(':usrcustomerid', $_SESSION['usrcustomerid'], PDO::PARAM_INT);
$stmt->execute();
break;
}
Edit
Please ignore.. #Bira's answer is more accurate
Try this:
$stmt = $db->prepare("UPDATE promocode_3 SET used = 1 WHERE coupon_code ='".$couponCode."'");
you missed the quote in coupon code value.
P.S. I don't know which database you are using. Please mention that next time. :)
This should work but it's not an ideal case for a prepared statement because in case of prepared statements you should give parameters only at the time of execution.
"prepare" should only compile an sql statement and parameters should be passed later on.
I've got a simple query that is not so easy to execute in PHP script:
SELECT `title` from `MY_TABLE` WHERE id in (30,32,33,44)
Usually I execute sql queries with prepared statements. I place a bunch of ? and than bind parameters. This time the numbers in parenthesis are an array of data I get from the user.
I tried this, but it does not work:
$ids = [30,32,33,44];
$stmt = $mysqli->prepare("
SELECT `title` from `MY_TABLE` WHERE id in (?)
");
// $stmt->bind_param();
$stmt->bind_param("i",$ids);
$stmt->execute();
$stmt->bind_result($title);
$stmt->store_result();
//fetch
How can I execute a set operation with prepared statements?
UPDATE:
After following your advice I came up with this
$ids = [30,32,33,44];
$questionMarks = rtrim(str_repeat('?,',count($ids)),", ");
$parameters = str_repeat('i',count($ids));
echo $questionMarks."<br>";
echo $parameters."<br>";
$stmt = $mysqli->prepare("
SELECT `title` from `MY_TABLE` WHERE id in (".$questionMarks.")
");
$scene_names = [];
$stmt->bind_param($parameters, $ids); //error here
$stmt->execute();
$stmt->bind_result($title);
$stmt->store_result();
I am still getting an error. This time it says:
Number of elements in type definition string doesn't match number of bind variables
I am not sure why it thinks that the number of elements (what is element in this case?) is wrong.
UPDATE 2:
Instead of:
$stmt->bind_param($parameters, $ids); //error here
I used:
$stmt->bind_param($parameters, ...$ids); //error gone
Taraam. Works fine.
Something like:
$ids = [30,32,33,44];
$types = array();
foreach($ids as $i){
array_push($types,'i');
}
$params = array_merge($ids,$types);
$sqlIN = str_repeat('?,',count($ids));
$sqlIN = rtrim($sqlIN, ',');
//Value of $sqlIN now looks like ?,?,?,?
$sql = "SELECT title from MY_TABLE WHERE id IN ($sqlIN)";
$stmt = $mysqli->prepare($sql);
call_user_func_array(array($stmt, 'bind_param'), $params);
$stmt->execute();
$stmt->bind_result($id);
$stmt->store_result();
I have a select where I have 3 results:
$stmt = $handler->prepare("SELECT id,comments,likes,views FROM sites WHERE usr_id = '$usr_id'");
$stmt->execute();
After this select I have 3 results. Now I want in another table update or insert a new row for each result
This is my complete code
I don't have any update or new insert in table. Can anybody please help me?
$stmt = $handler->prepare("SELECT id,comments,likes,views FROM sites WHERE usr_id = '$usr_id'");
$stmt->execute();
while($row = $stmt->fetch(PDO::FETCH_ASSOC)){
$rows[]=$row;
foreach($rows as $row){
$site_id = $row[id];
$stmt = $handler->prepare("SELECT id FROM session WHERE site_id = '$site_id' AND usr_id = '$usr_id'");
$stmt->execute();
$no=$stmt->rowCount();
if ($no > 0)
{
$stmt = $handler->prepare("UPDATE session SET comments = '$comments' , likes = '$likes' , views = '$views' WHERE usr_id = $usr_id AND site_id = $site_id");
$stmt->execute();
}
else
{
$stmt = $handler->prepare("INSERT INTO session(user_id,site_id,comments,likes,views)VALUES('$user_id','$site_id','$comments','$likes','$views')");
$stmt->execute();
}
}
}
First issue, you weren't taking advantage of prepared statements at all. Use parameters (the ? in the query) and then fill them with values in the execute() call.
Also, prepare your query outside a loop, and execute it inside. This is one of the key advantages of preparing statements in advance, there is less overhead when they are only prepared once.
Finally, there's no need for checking the database before your query and then executing one of two queries. Just let MySQL check if the value exists already with INSERT...ON DUPLICATE KEY UPDATE syntax. This relies on the database being set up properly, so there should be a UNIQUE index on (session.usr_id, session.site_id).
This is untested, but should get you going:
$stmt1 = $handler->prepare("SELECT id,comments,likes,views FROM sites WHERE usr_id = ?");
$stmt2 = $handler->prepare("INSERT INTO session SET comments = ?, likes = ?, views = ?, usr_id = ?, site_id = ? ON DUPLICATE KEY UPDATE comments = VALUES(comments), likes = VALUES(likes), views = VALUES(views)");
$stmt1->execute(array($usr_id));
while($row = $stmt1->fetch(PDO::FETCH_ASSOC)) {
$site_id = $row["id"];
$stmt2->execute(array($comments, $likes, $views, $usr_id, $site_id));
}
#Miken32's answer would be the ideal way.
A direct fix to your code would be this way:
$stmt1 = $handler->prepare("SELECT id,comments,likes,views FROM sites WHERE usr_id = :usr_id");
$stmt1->bindValue(':usr_id', $usr_id);
$stmt1->execute();
while ($row = $stmt1->fetch(PDO::FETCH_ASSOC)) {
$stmt2 = $handler->prepare("SELECT id FROM session WHERE site_id = :site_id AND usr_id = :usr_id");
$stmt2->bindValue(':usr_id', $usr_id);
$stmt2->bindValue(':site_id', $row['id']);
$stmt2->execute();
if ($stmt2->rowCount() > 0) {
$stmt3 = $handler->prepare("UPDATE session SET comments = :comments , likes = :likes , views = :views WHERE usr_id = :usr_id AND site_id = :site_id");
} else {
$stmt3 = $handler->prepare("INSERT INTO session(user_id,site_id,comments,likes,views)VALUES(:usr_id,:site_id,:comments,:likes,:views)");
}
$stmt3->bindValue(':comments', $row['comments']);
$stmt3->bindValue(':likes', $row['likes']);
$stmt3->bindValue(':views', $row['views']);
$stmt3->bindValue(':usr_id', $usr_id);
$stmt3->bindValue(':site_id', $row['id']);
$stmt3->execute();
}
But this is not the best way to go about it. INSERT ...UPDATE ON DUPLICATE KEY would be better.
So i think i'm close to figuring this out but my query won't add the item from the "pending" table to the "items" table. can you guys help me out with this please. Also if i want it to delete after it gets added should i add the code below the INSERT INTO SELECT query? thanks
action.php:
$sql = "INSERT INTO items (photo,title,description, name) SELECT (photo,title,description, name) FROM pending";
$stmt = $conn->prepare($sql);
$stmt->execute();
Example for delete query after it takes the item from the "pending" into items:
$idToDelete = filter_var($_POST["recordToDelete"],FILTER_SANITIZE_NUMBER_INT);
//try deleting record using the record ID we received from POST
$sql = "DELETE FROM pending WHERE id = :id";
$stmt = $conn->prepare($sql);
$stmt->bindParam(':id', $idToDelete, PDO::PARAM_INT);
$stmt->execute();
I think you are leaving yourself open to mistakes doing it this way.
Consider what would happen if a new row is added to the pending queue after you have issued the INSERT SELECT but before you have started your delete.
I think you need to do this in a more controlled way inside a single loop to make sure you are only deleting what you have copied from pending into items.
$sql = "SELECT photo,title,description, name FROM pending";
$select_pending = $conn->prepare($sql);
$select_pending->execute();
$sql = "INSERT INTO items (photo,title,description, name)
VALUES (:photo,:title,:description, :name)";
$insert_items = $conn->prepare($sql);
$sql = "DELETE FROM pending WHERE id = :id";
$delete_pending = $conn->prepare($sql);
// only if you are using INNODB databases.
//$conn->beginTransaction();
while( $row = $select_pending->fetch_object() ) {
$insert_items->bindParam(':photo', $row->photo, PDO::PARAM_STR);
$insert_items->bindParam(':title', $row->title, PDO::PARAM_STR);
$insert_items->bindParam(':description', $row->description, PDO::PARAM_STR);
$insert_items->bindParam(':name', $row->name, PDO::PARAM_STR);
$insert_items->execute();
$delete_pending->bind_param(':id', $row->id, PDO::PARAM_INT);
$delete_pending->execute();
}
// only if you are using INNODB databases.
//$conn->commit();
$sql = "INSERT INTO items (photo,title,description, name)
SELECT photo,title,description, name FROM pending";
remove the () in the SELECT statement.
I've tried following the PHP.net instructions for doing SELECT queries but I am not sure the best way to go about doing this.
I would like to use a parameterized SELECT query, if possible, to return the ID in a table where the name field matches the parameter. This should return one ID because it will be unique.
I would then like to use that ID for an INSERT into another table, so I will need to determine if it was successful or not.
I also read that you can prepare the queries for reuse but I wasn't sure how this helps.
You select data like this:
$db = new PDO("...");
$statement = $db->prepare("select id from some_table where name = :name");
$statement->execute(array(':name' => "Jimbo"));
$row = $statement->fetch(); // Use fetchAll() if you want all results, or just iterate over the statement, since it implements Iterator
You insert in the same way:
$statement = $db->prepare("insert into some_other_table (some_id) values (:some_id)");
$statement->execute(array(':some_id' => $row['id']));
I recommend that you configure PDO to throw exceptions upon error. You would then get a PDOException if any of the queries fail - No need to check explicitly. To turn on exceptions, call this just after you've created the $db object:
$db = new PDO("...");
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
I've been working with PDO lately and the answer above is completely right, but I just wanted to document that the following works as well.
$nametosearch = "Tobias";
$conn = new PDO("server", "username", "password");
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sth = $conn->prepare("SELECT `id` from `tablename` WHERE `name` = :name");
$sth->bindParam(':name', $nametosearch);
// Or sth->bindParam(':name', $_POST['namefromform']); depending on application
$sth->execute();
You can use the bindParam or bindValue methods to help prepare your statement.
It makes things more clear on first sight instead of doing $check->execute(array(':name' => $name)); Especially if you are binding multiple values/variables.
Check the clear, easy to read example below:
$q = $db->prepare("SELECT id FROM table WHERE forename = :forename and surname = :surname LIMIT 1");
$q->bindValue(':forename', 'Joe');
$q->bindValue(':surname', 'Bloggs');
$q->execute();
if ($q->rowCount() > 0){
$check = $q->fetch(PDO::FETCH_ASSOC);
$row_id = $check['id'];
// do something
}
If you are expecting multiple rows remove the LIMIT 1 and change the fetch method into fetchAll:
$q = $db->prepare("SELECT id FROM table WHERE forename = :forename and surname = :surname");// removed limit 1
$q->bindValue(':forename', 'Joe');
$q->bindValue(':surname', 'Bloggs');
$q->execute();
if ($q->rowCount() > 0){
$check = $q->fetchAll(PDO::FETCH_ASSOC);
//$check will now hold an array of returned rows.
//let's say we need the second result, i.e. index of 1
$row_id = $check[1]['id'];
// do something
}
A litle bit complete answer is here with all ready for use:
$sql = "SELECT `username` FROM `users` WHERE `id` = :id";
$q = $dbh->prepare($sql);
$q->execute(array(':id' => "4"));
$done= $q->fetch();
echo $done[0];
Here $dbh is PDO db connecter, and based on id from table users we've get the username using fetch();
I hope this help someone, Enjoy!
Method 1:USE PDO query method
$stmt = $db->query('SELECT id FROM Employee where name ="'.$name.'"');
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
Getting Row Count
$stmt = $db->query('SELECT id FROM Employee where name ="'.$name.'"');
$row_count = $stmt->rowCount();
echo $row_count.' rows selected';
Method 2: Statements With Parameters
$stmt = $db->prepare("SELECT id FROM Employee WHERE name=?");
$stmt->execute(array($name));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
Method 3:Bind parameters
$stmt = $db->prepare("SELECT id FROM Employee WHERE name=?");
$stmt->bindValue(1, $name, PDO::PARAM_STR);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
**bind with named parameters**
$stmt = $db->prepare("SELECT id FROM Employee WHERE name=:name");
$stmt->bindValue(':name', $name, PDO::PARAM_STR);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
or
$stmt = $db->prepare("SELECT id FROM Employee WHERE name=:name");
$stmt->execute(array(':name' => $name));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
Want to know more look at this link
if you are using inline coding in single page and not using oops than go with this full example, it will sure help
//connect to the db
$dbh = new PDO('mysql:host=localhost;dbname=mydb', dbuser, dbpw);
//build the query
$query="SELECT field1, field2
FROM ubertable
WHERE field1 > 6969";
//execute the query
$data = $dbh->query($query);
//convert result resource to array
$result = $data->fetchAll(PDO::FETCH_ASSOC);
//view the entire array (for testing)
print_r($result);
//display array elements
foreach($result as $output) {
echo output[field1] . " " . output[field1] . "<br />";
}