PDO with bound parameters sql query If statement in update - php

I am attempting to create a 'trigger' not in the sql sense but I want to update the date_added field when the status field is set to 100
$sql='UPDATE table
SET status=:status,
date_added=[PSEUDO CODE :status=100 ? now() : null;]
WHERE id=:id';
$stmt=$conn->prepare($sql);
$stmt->bindParam(':id', $id, PDO::PARAM_STR);
$stmt->bindParam(':status', $status, PDO::PARAM_STR);
$stmt->bindParam(':sign_id', $sign_id, PDO::PARAM_STR);
$stmt->execute();
Would it be better to attempt this in the sql query(unsure how to
perform this) or on the php page (think I could stumble through
that one) prior to issuing the query?
Are there any performance gains one way or the other?
Thanks in advance for any help

date_added = :date
$date = $status == 100 ? date('Y-m-d H:i:s') : null;
$stmt->bindParam(":date", $date);
You can do this comparison in MySQL as well using IF. I don't think that one is particularly faster than the other, but it makes more sense to me to use PHP for the comparison.

This should work:
$sql='UPDATE table
SET status=:status,
date_added=IF(:status=100, NOW(), NULL)
WHERE id=:id';
$stmt=$conn->prepare($sql);
$stmt->bindParam(':id', $id);
$stmt->bindParam(':status', $status);
$stmt->execute();
But using the same parameter name twice in one statement only works if you configure PDO to use emulated prepare. If you use native prepare, then you should make distinct parameter names even for the same value:
$sql='UPDATE table
SET status=:status,
date_added=IF(:status_again=100, NOW(), NULL)
WHERE id=:id';
$stmt=$conn->prepare($sql);
$stmt->bindParam(':id', $id);
$stmt->bindParam(':status', $status);
$stmt->bindParam(':status_again', $status);
$stmt->execute();
Or else it'd be simpler to use positional parameters. You can also skip the bindParam() if you just pass an array of values to execute(). There's an example of the latter two changes together:
$sql='UPDATE table
SET status=?,
date_added=IF(?=100, NOW(), NULL)
WHERE id=?';
$stmt=$conn->prepare($sql);
$stmt->execute([$status, $status, $id]);

Related

MySQLi prepared statement not binding integer

I'm new to prepared statements. Sql query is working fine if i insert dummy data and it is working without binding the integer($id).
Where am i wrong?
sql = "UPDATE staff_type SET s_type=?, description=? WHERE s_type_id=?;";
$stmt = mysqli_stmt_init($conn);
mysqli_stmt_prepare($stmt, $sql));
mysqli_stmt_bind_param($stmt, "ssi", $type, $desc, $id);
mysqli_stmt_execute($stmt);
I found the error which cause the integer parameter to not bind. I didn't know that disabled input fields cannot post data, therefore i found a solution to replace the 'disabled' attribute with 'readonly'.
Before binding parameters you have to Prepare an SQL statement with parameters in it.
$sql = "UPDATE staff_type SET s_type=?, description=? WHERE s_type_id=?;";
$stmt = $conn->prepare($sql);
$stmt->bind_param("ssi", $type, $desc, $id);
$stmt->execute();
You have to Prepare Statement first
**Procedural style**
$stmt = mysqli_prepare($conn, "UPDATE staff_type SET s_type=?, description=? WHERE s_type_id=?");
mysqli_stmt_bind_param($stmt, "ssi", $type, $desc, $id);
mysqli_stmt_execute($stmt);
check http://php.net/manual/en/mysqli-stmt.bind-param.php
Try this
$sql= $con->prepare("update staff_type set s_type=?, description=? WHERE s_type_id = ?");
if ($result){
$sql->bind_param('ssi', $s_type, $desc, $s_type_id );
$sql->execute();
}
side note: s represents string while i represents integer
Hope this helps you

Invalid parameter number for PDO statement

Next code gives me an error SQLSTATE[HY093]: Invalid parameter number
$sql = "INSERT INTO `users` (`id`, `date_install`, `date_ping`, `cc`, `uv`, `pid`, `pv`, `aff_id`, `sub_id`, `channel`, `cid`, `os`, `av`, `db`) VALUES (:id, :date_install, now(), :country, :updaterVersion, :productId, :productVersion, :affiliateId, :subId, :channel, :commandId, :os, :av, :defaultBrowser) "
. "ON DUPLICATE KEY UPDATE `date_install` = :date_install, `date_ping` = now(), `cc` = :country, `uv` = :updaterVersion, `pid` = :productId, `pv` = :productVersion, `aff_id` = :affiliateId, `sub_id` = :subId, `channel` = :channel, `cid` = :commandId, `os` = :os, `av` = :av, `db` = :defaultBrowser ";
$statement = $database->prepare($sql);
$statement->bindValue(":id", $user->id, PDO::PARAM_INT);
$statement->bindValue(":date_install", $user->date_install, PDO::PARAM_STR);
$statement->bindValue(":country", $user->cc, PDO::PARAM_STR);
$statement->bindValue(":updaterVersion", $user->uv, PDO::PARAM_INT);
$statement->bindValue(":productId", $user->pid, PDO::PARAM_INT);
$statement->bindValue(":productVersion", $user->pv, PDO::PARAM_INT);
$statement->bindValue(":affiliateId", $user->aff_id, PDO::PARAM_INT);
$statement->bindValue(":subId", $user->sub_id, PDO::PARAM_INT);
$statement->bindValue(":channel", $user->channel, PDO::PARAM_STR);
$statement->bindValue(":commandId", $user->cid, PDO::PARAM_INT);
$statement->bindValue(":os", $user->os, PDO::PARAM_STR);
$statement->bindValue(":av", $user->av, PDO::PARAM_STR);
$statement->bindValue(":defaultBrowser", $user->db, PDO::PARAM_STR);
$statement->execute();
I have no idea what is wrong and if I copy/paste SQL into console and replace all values manually everything works. Also if I comment out part ON DUPLICATE KEY..., also works.
If emulation mode is turned off for your PDO instance, you won't be able to use the same placeholder name more than once in the query.
Besides, for the ON DUPLICATE it is not necessary either, as you can always use the VALUES operator that will take the value from the VALUES clause:
ON DUPLICATE KEY UPDATE `date_install` = VALUES(date_install), ...
PDO Doesn't allow repetition of variable names. Your ON DUPLICATE KEY UPDATE should have it's own variable names. Which also means you have to assign your variables 2 times. This is a sad limitation :(.
In order to use the same parameter names twice, you must set PDO::ATTR_EMULATE_PREPARES attribute to true:
$database->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);

Is it okay to always use same variable (e.g. $stmt) for PDO queries?

I always use the same variable for my PDO query statements, for example:
// Query 1
$stmt = $db->prepare("UPDATE table_1 SET name=? WHERE somthing=?");
$stmt->bindValue(1, $name, PDO::PARAM_STR);
$stmt->bindValue(2, $something, PDO::PARAM_STR);
$stmt->execute();
// Query 2 (right after the above)
$stmt = $db->prepare("UPDATE table_2 SET another_column=? WHERE id=?");
$stmt->bindValue(1, $another_column, PDO::PARAM_STR);
$stmt->bindValue(2, $id, PDO::PARAM_INT);
$stmt->execute();
I know it is ok for the first lines ($stmt = $db->...), my doubt is about binding values. For example if I forget to bind something in first query will my query use the next binding in second query (or vice versa)? or everything is reset after execute()?
Which one is a better practice?
Using same variable to avoid mistakes (e.g. Always $stmt)
Using different variables
Using different variables makes it easier to debug, however I do this occasionally because it is easier to type-hint a single statement.
my doubt is about binding values.
each db->prepare() returns a brand new \PDOStatement so there is no issue about binding values.
In cases like this, different statements used in the same scope, I choose more specific names for the statements.
So in your case I would name them $stmtUpdTable1 and $stmtUpdTable2 or something along those lines.
Since I can't comment other answers: I think it is unnecessary to unset variables which are no longer used, the garbage collector will do his job. No need to make the code messy
I would prefer to unset $stmt after each query. So I don't have to worry about all the things which you have mentioned above.
// Query 1
$stmt = $db->prepare("UPDATE table_1 SET name=? WHERE somthing=?");
$stmt->bindValue(1, $name, PDO::PARAM_STR);
$stmt->bindValue(2, $something, PDO::PARAM_STR);
$stmt->execute();
unset($stmt);
// Query 2 (right after the above)
$stmt = $db->prepare("UPDATE table_2 SET another_column=? WHERE id=?");
$stmt->bindValue(1, $another_column, PDO::PARAM_STR);
$stmt->bindValue(2, $id, PDO::PARAM_INT);
$stmt->execute();
Also its a good practice to unset variable which are not required any more.

PHP PDO bindParam() and MySQL BIT

I'm trying to update data in a table with a BIT type value in it, like the following :
// $show_contact is either '1' or '0'
$query->bindValue(':scontact', $show_contact, PDO::PARAM_INT);
The problem is, it never changes the value, it remains '1' as set on PHPMyAdmin. I tried different PDO::PARAM_ types without success, everything else is working.
edit full script
$sql = "UPDATE users SET password = :password, address = :address, postal = :postal, city = :city, contact = :contact, show_contact = :scontact WHERE id = :id";
$query = $dbh->prepare($sql);
$query->bindValue(':id', $user->id, PDO::PARAM_INT);
$query->bindValue(':password', md5($password), PDO::PARAM_STR);
$query->bindValue(':address', $address, PDO::PARAM_STR);
$query->bindValue(':postal', $postal, PDO::PARAM_STR);
$query->bindValue(':city', $city, PDO::PARAM_STR);
$query->bindValue(':contact', $contact, PDO::PARAM_STR);
$query->bindValue(':scontact', $show_contact, PDO::PARAM_INT);
$query->execute();
PDO has a bit of a bug where any parameter passed to a query, even when specifically given as PDO::PARAM_INT is treated as a string and enclosed with quotes. READ THIS
The only way to tackle it is to try the following:
$show_contact = (int)$show_contact;
$query->bindValue(':scontact', $show_contact, PDO::PARAM_INT);
I believe that the BIT type is mapped to PDO's PARAM_BOOL. Try using it with strictly boolean input.
$show_contact = (bool) $show_contact; // '0' => FALSE, '1' => TRUE
$query->bindValue(':scontact', $show_contact, PDO::PARAM_BOOL);

A better way to do this?

So this is my current code:
function addPage($uniquename, $ordernum, $title, $author, $content, $privilege, $description=NULL, $keywords=NULL){
if (!$description) $description = NULL;
if (!$keywords) $keywords = NULL;
//UPDATE `table` SET `ordernum` = `ordernum` + 1 WHERE `ordernum` >= 2
$query = "UPDATE ".$this->prefix."page SET ordernum = ordernum+1 WHERE ordernum >= ?";
if ($stmt = $this->db->prepare($query)){
$stmt->bind_param("i", $ordernum);
$stmt->execute();
if (!arCheck($stmt)) return false;
} else {
$this->stmtError("addPage", $stmt->error);
}
$query = "INSERT INTO ".$this->prefix."page VALUES (LCASE(?), ?, ?, ?, ?, ?, ?, ?)";
if ($stmt = $this->db->prepare($query)){
$stmt->bind_param("sisisssi", $uniquename, $ordernum, $title, $author, $content, $description, $keywords, $privilege);
$stmt->execute();
return arCheck($stmt);
} else {
$this->stmtError("addPage", $stmt->error);
}
}
It is suppose to add a new page to the datatable. The MySQL is courtesy of Phil Hunt from Store the order of something in MySQL
I know that you can use multiquery to accomplish the same thing, however I was told that prepared statement is better in performance, and security. Is there another way to do this? Like a prepared multi query?
Also, what about doing Transactions? I'm not fully sure of what that is, I assume that it's if, let's say, the INSERT statement fails, it will undo the UPDATE statement as well?
NOTE: the arCheck function will close the statement.
Prepared statements are indeed faster for repeated queries, at least in most cases. They're also safer because they automatically escape input values, preventing SQL injection attacks. If you want to use them in PHP you'll need the MySQLi extension.
You appear to have the right idea about transactions. With MySQLi there are commit and rollback methods, otherwise you can use mysql_query("COMMIT") or mysql_query("ROLLBACK").

Categories