I have a web program which allows the administrator to update a user's information... With that being said, I only want columns updated which have indeed been 'updated'...
I have done quite a bit of researching on this and it seems that all methods use outdated querys, which do not make use of the prepare statement to escape input...
Can someone please help me with the statement?
Essentially in psuedocode:
Update FIRSTNAME if $editedUserdata['firstname'] != FIRSTNAME, LASTNAME if $editedUserData['lastname'] != LASTNAME ...etc...
Here is what I have for the post code...
$password = sha1($password);
$editedUserData = array(
'firstname' => $firstname,
'lastname' => $lastname,
'username' => $username,
'password' => $password,
'cellphone' => $cellphone,
'security_level' => $seclvl,
'email' => $email,
'direct_phone' => $direct,
'ext_num' => $extension,
'is_active' => $userflag
);
Then it should be something like
$query = $this->db->prepare('UPDATE FIRSTNAME if(?) IS NOT FIRSTNAME, LASTNAME if(?) IS NOT LASTNAME, USERNAME if (?) IS NOT USERNAME.... VALUES (:firstname, :lastname, :username).....'
if ($query -> execute($editedUserData)) {
more code....
According to MySQL documentation -
Ref: (http://dev.mysql.com/doc/refman/5.0/en/update.html)
"If you set a column to the value it currently has,
MySQL notices this and does not update it."
Maybe I'm not understanding the problem which you're trying to solve but you don't have to test if field value did change.
If field value is "A" and you put there an "A" it will remain the same otherwise, if you put there a "B" it will be updated as expected
The prepared statement would be something like
$stmt = $dbh->prepare("
UPDATE table_name
SET
field1 = :value1,
field2 = :value2
WHERE
field0 = :key
");
$stmt->bindParam(':value1', $value1, PDO::PARAM_STR);
$stmt->bindParam(':value2', $value2, PDO::PARAM_STR);
$stmt->bindParam(':key', $key, PDO::PARAM_INT);
$stmt->execute()
Run a single statement to update the row.
Firstly, what's the unique identifier for a row in the users table, is there a unique userid or username? You'll want a WHERE clause on the UPDATE statement so that only that row will be updated.
The normative pattern for an UPDATE statement to update several columns in a single row is like this:
UPDATE users
SET col2 = 'value'
, col3 = 'another value'
, col4 = 'fi'
WHERE idcol = idvalue ;
To use a prepared statement with PDO, the SQL text could look something like this, if you use named placeholders:
UPDATE users
SET col2 = :col2_value
, col3 = :col3_value
, col4 = :col4_value
WHERE idcol = :id_value
Or this, if you use positional notation for the placeholders:
UPDATE users
SET col2 = ?
, col3 = ?
, col4 = ?
WHERE idcol = ?
(My personal preference is to use the named placeholders, rather than positional, but either will work.)
This is how I'd do it, run the prepare, then the bind_param, and then the execute.
$sql = "UPDATE users
SET col2 = :col2_value
, col3 = :col3_value
, col4 = :col4_value
WHERE idcol = :id_value ";
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':col2_value', $col2_val, PDO::PARAM_STR);
$stmt->bindParam(':col3_value', $col3_val, PDO::PARAM_STR);
$stmt->bindParam(':col4_value', $col4_val, PDO::PARAM_STR);
$stmt->bindParam(':id_value' , $id_val, PDO::PARAM_STR);
$stmt->execute();
To do something different, to dynamically create the SQL text, and adjust the bindParam calls, that would add unnecessary complexity to the code. There's no performance advantage to doing that; when that UPDATE statement runs, MySQL has to lock the row, store a new copy of the row. It doesn't really save anything (aside from a few bytes of data transfer) to avoid sending a column value that hasn't changed.
If you realy want to use cases, read this.
There is no reason to do it in your case, as stated from #spencer7593 in the comments:
That's WAY more overhead... roundtrips to the database, parsing the
statement, developing an execution plan, executing the statement,
obtaining locks, returning a status, client checking the status, etc.
That's just seems an all-around inefficient approach.
I assume that any RDBMS is smart enough, to notice, that Caches etc should not be recalculated (if nothing changes), if that is the problem.
Related
I have two queries and I want to combine them into one so that it only returns one row in my database.
I have tried UNION but I keep getting an error. Can anyone please advise me on the code for it?
Below are my queries:
if(isset($_POST["response"]))
{
$query = "INSERT INTO response(response) VALUES (:response)";
$statement = $conn->prepare($query);
$statement->execute(
array(
':response' => $_POST["response"]
)
);
$query = " INSERT INTO response (student_id)
SELECT studentid
FROM student
WHERE studentid = '".$_SESSION['studentid']."'";
$statement = $conn->prepare($query);
$statement->execute(
);
UNION is used for combining multiple SELECT queries into a single result set. Check the mySQL (or any generic ANSI SQL) documentation.
Anyway, for no apparent reason you are making two INSERT queries when it looks like you're inserting into the same table and presumably want to insert everything into the same row in the same table. Right now you will make 2 rows instead of 1. You can insert more than one field as part of a single query.
I'm thinking:
if(isset($_POST["response"]))
{
$query = "INSERT INTO response (student_id, response) SELECT studentid, :response FROM student WHERE studentid = :studentID";
$statement = $conn->prepare($query);
$statement->execute(
array(
':response' => $_POST["response"],
':studentID' => $_SESSION['studentid']
)
);
}
However, since you only require the studentID in the table, and you already have the studentID from the session, it seems pointless to select from the students table at all. The only exception might be if you need to verify that the value in the session is correct - but surely you have already verified it before you added it to the session? If you haven't, you certainly should.
So in fact simply
if(isset($_POST["response"]))
{
$query = "INSERT INTO response (student_id, response) VALUES (:studentID, :response)";
$statement = $conn->prepare($query);
$statement->execute(
array(
':response' => $_POST["response"],
':studentID' => $_SESSION['studentid']
)
);
}
should be sufficient.
I don't know how to update or insert multiple rows by using PDO. Please help me.
Something that is in my mind is:
$stmt = $dbh->query("update_line_1; update_line_2; update_line_3");
//update_line_1: update table a set a.column1 = "s1" where a.id = 1
//update_line_2: update table a set a.column1 = "s2" where a.id = 2
//....
$stm = $dbh->query("insert_line_1; insert_line_3; insert_line_3");
//something is like the update line above.
I don't know this way works or not. And If you have another way, please let me know. Thank you so so much.
And if I use prepare statement, I just update each row each time. (This is much more safe than above)
$stmt = $dbh->prepare("update table a set a.colum1 = :column1 where a.id = :id");
$stmt->bindParam(":column1","s1");
$stmt->bindparam(":id",1);
$stmt->execute();
The most hate thing I don't want to do is using a loop goes through all elements in an array, and update or insert each element each time
Is another way to mass safely update or insert multiple rows to database? thank for your help.
Sorry about my English.
For inserts, you can insert multiple rows worth of data with the following syntax:
INSERT INTO table (col1, col2, col3)
VALUES
('1', '2', '3'),
('a', 'b', 'c'),
('foo', 'bar', 'baz')
For updates, the update will by default effect as many rows as meet the criteria of the query. So something like this would update an entire table
UPDATE table SET col = 'a'
If you are trying to update different values for each row, you don't really have much of a choice other than to do a query for each operation. I would suggest however that, building on your PDO example, you could do something like this:
$update_array = array(
1 => 'foo',
2 => 'bar',
10 => 'baz'
); // key is row id, value is value to be updated
$stmt = $dbh->prepare("UPDATE table SET column1 = :column1 where id = :id");
$stmt->bindParam(":column1",$column_value);
$stmt->bindparam(":id",$id);
foreach($update_array as $k => $v) {
$id = $k
$column_value = $v;
$stmt->execute();
// add error handling here
}
With this approach you are at least leveraging the use of the prepared statement to minimize query overhead.
...i am not getting any further.
my database contains a column 'name' = 'John Richards'
i try to query it like:
$act = "John Richards";
prepareEditing($act);
function prepareEditing($act) {
include ($_SERVER['DOCUMENT_ROOT']."/final_ritg/includes/dbconnect.php");
$act = str_replace(" ", " ", $act);
$sql = "select `name`,`genre`, `members`, `story`, `image`, `contact_fname`, `contact_lname`, `contact_phone`, `contact_email` from `festival`.`act` where `name` = :name ;";
$stmt = $pdo->prepare($sql);
$stmt->bindParam(':name', $act);
$stmt->execute();
echo $stmt->rowCount();
}
when 'name' only contains a single word, like 'john', the function returns 1 ($act holds 'john' as well).
How do I have to prepare my query?
Edit: I am using utf8 across the board.
Edit: This is the prepare stmt I use to insert the data:
$stmt->bindParam(':name', str_replace(' ',' ',$name));
I did so, because the query result would have been cut off at the whitespace when trying to retrieve it.
As it turns out, my mistake was not in the php, but inside the html.
I was creating a select list from a table. because the names were unique, i used those as primary keys and as value for each select-option...those dont like whitespace.
The solution here would be to either add a numbered index to the table or to do some string-conversion (but that would cause a lot of extra work preparing the string for the query) I dont yet know how I would be going over this.
Anyways, maybe another beginner runs into the same trap and finds this useful.
Is it possible to submit data to two tables with the same query?
My existing code looks like this:
private function adduser() {
if (!empty($this->error)) return false;
$params = array(
':user_level' => parent::getOption('default-level'),
':name' => $this->name,
':email' => $this->email,
':username' => $this->username,
':password' => parent::hashPassword($this->password)
);
parent::query("INSERT INTO `login_users` (`user_level`, `name`, `email`, `username`, `password`)
VALUES (:user_level, :name, :email, :username, :password);", $params);
I didn't write this code so it is a bit confusing to me as I don't usually use PDO. What I would like to do in addition to this is add two values to my 'url_alias' table, the first is the UID (which is auto incremented from the first query) and the second is another variable value.
All of the examples I have found while searching dont seem to work for me because of the way this existing code looks.
Can anyone give me a hand?
It doesn't matter what db driver your are using (PDO, Mysqli, etc.) you question is purely about mysql capabilities. Mysql may update and delete rows from multiple tables in a single query but not insert. I.e. INSERT table_1, table_2 ... is not allowed.
You have to run one query for each table you want to insert data.
So I am trying to change the status of something when values are met using WHERE
Code:
$insertstatus = $DBH->prepare("INSERT INTO
csvdata (status) VALUES ('$status') WHERE username = '".$username."'");
$insertstatus->execute();
Not working. If you could give me a hand.
Thank you for your time!
If you want to use the where clause, you need to use update. From the looks of it, you are trying to update anyhow as you are only using one column from your table.
$insertstatus = $DBH->prepare("update
csvdata set status= '$status' WHERE username = '".$username."'");
$insertstatus->execute();
As PeeHaa correctly points out though, using a prepared statement with parameters would be a slight change in your code, and a better option for you. You can do it like this:
$sql="update csvdata set status=:status where username=:username";
$sth=$DBH->prepare($sql);
$sth->execute(array(':status' => $status, ':username' => $username));
This way you are preparing the statement so the database knows what will happen. You then pass the variables to the database via the execute() function in an array.