PDO "ON DUPLICATE KEY UPDATE" prepared statement [duplicate] - php

This question already has answers here:
SQLite INSERT - ON DUPLICATE KEY UPDATE (UPSERT)
(5 answers)
Closed 7 years ago.
I am attempting a prepared statement for the first time based on this thread. So far I am getting the error message SQLSTATE[HY000]: General error: 1 near "ON": syntax error Here is the query followed by the try block:
$query = "INSERT INTO results2015_2016 ('id','ata','atc','atcommon','atn','ats','atsog','hta','htc','htcommon','htn','hts','htsog','bs','bsc','canationalbroadcasts','gcl','gcl1','gs','r1','usnationalbroadcasts')
VALUES (':id',':ata',':atc',':atcommon',':atn',':ats',':atsog',':hta',':htc',':htcommon',':htn',':hts',':htsog',':bs',':bsc',':canationalbroadcasts',':gcl',':gcl1',':gs',':r1',':usNationalBroadcasts')
ON DUPLICATE KEY UPDATE id= ':id2'";
try {
$db = new PDO('db info');
$db->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
$stmt = $db->prepare($query);
$stmt->bindParam(':ata', $ata, PDO::PARAM_STR);
$stmt->bindParam(':atc' , $atc , PDO::PARAM_STR);
$stmt->bindParam(':atcommon', $atCommon , PDO::PARAM_STR);
$stmt->bindParam(':atn', $atn , PDO::PARAM_STR);
$stmt->bindParam(':ats', $ats , PDO::PARAM_INT);
$stmt->bindParam(':atsog', $atsog , PDO::PARAM_INT);
$stmt->bindParam(':hta', $hta , PDO::PARAM_STR);
$stmt->bindParam(':htc', $htc , PDO::PARAM_STR);
$stmt->bindParam(':htcommon', $htCommon , PDO::PARAM_STR);
$stmt->bindParam(':htn', $htn , PDO::PARAM_STR);
$stmt->bindParam(':hts', $hts , PDO::PARAM_INT);
$stmt->bindParam(':htsog', $htsog , PDO::PARAM_INT);
$stmt->bindParam(':bs', $bs , PDO::PARAM_STR);
$stmt->bindParam(':bsc', $bsc , PDO::PARAM_STR);
$stmt->bindParam(':canationalbroadcasts', $caNationalBroadcasts , PDO::PARAM_STR);
$stmt->bindParam(':gcl', $glc , PDO::PARAM_BOOL);
$stmt->bindParam(':gcl1', $glc1 , PDO::PARAM_BOOL);
$stmt->bindParam(':gs', $gs , PDO::PARAM_INT);
$stmt->bindParam(':r1', $r1 , PDO::PARAM_BOOL);
$stmt->bindParam(':usnationalbroadcasts', $usNationalBroadcasts , PDO::PARAM_STR);
$stmt->bindParam(':id', $idGame , PDO::PARAM_INT);
$stmt->bindParam(':id2', $idGame , PDO::PARAM_INT);
$stmt->execute();
} catch (Exception $e) {
echo $e->getMessage();
exit;
}
I can't seem to find much on this error message and what it has to do with my situation. This code is within a loop parsing jsonp...I can post the entire code if needed.

When using a prepared statement, you do not need to enclose your parameters inside any kind of quotes. That will be taken care of by the engine itself:
$query = "INSERT INTO x(a,b,c,d) VALUES(:a, :b, :c, :d)";

As noted by #HJPotter92 - the placeholders in the sql should not be quoted and it should also be noted that field names should be enclosed with backticks rather than single quotes ( or nothing if the names are not considered reserved & don't contain spaces etc )
$query = "insert into results2015_2016 (
`id`,`ata`,`atc`,`atcommon`,`atn`,`ats`,`atsog`,`hta`,
`htc`,`htcommon`,`htn`,`hts`,`htsog`,`bs`,`bsc`,`canationalbroadcasts`,`gcl`,`gcl1`,
`gs`,`r1`,`usnationalbroadcasts`
) values (
:id,:ata,:atc,:atcommon,:atn,:ats,:atsog,:hta,:htc,:htcommon,:htn,:hts,
:htsog,:bs,:bsc,:canationalbroadcasts,:gcl,:gcl1,:gs,:r1,:usnationalbroadcasts
) on duplicate key update id=:id2";

Related

Someone kindly help me here: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens

public function register($uname,$age,$sex,$image,$dpart,$joind,$job,$uposition,$phone,$umail,$upass,
$unumber,$address,$nssf,$bank,$passp,$home,$village,$nation,$permit)
{
try
{
$new_password = password_hash($upass, PASSWORD_DEFAULT);
$stmt = $this->conn->prepare("INSERT INTO users(user_name,birth,gender,image,job_title,curr_position,telephone,department,joining_date,user_email,user_pass,box_number,residence,nssf_number,bank_account,passport_number,home_district,village,nationality,work_permit)
VALUES(:uname,:age,:sex,:image,:dpart,:joind,:job,:uposition,:phone,:umail,:upass,:unumber,:nssf,:bank,:passp,:home,:village,:nation,:permit)");
$stmt->bindparam(":uname",$uname);
$stmt->bindparam(":age",$age);
$stmt->bindparam(":sex",$sex);
$stmt->bindparam(":image",$image);
$stmt->bindparam(":dpart",$dpart);
$stmt->bindparam(":joind",$joind);
$stmt->bindparam(":job",$job);
$stmt->bindparam(":uposition",$uposition);
$stmt->bindparam(":phone",$phone);
$stmt->bindparam(":umail",$umail);
$stmt->bindparam(":upass",$new_password);
$stmt->bindparam(":unumber",$unumber);
$stmt->bindparam(":address",$address);
$stmt->bindparam(":nssf",$nssf);
$stmt->bindparam(":bank",$bank);
$stmt->bindparam(":passp",$passp);
$stmt->bindparam(":home",$home);
$stmt->bindparam(":village",$village);
$stmt->bindparam(":nation",$nation);
$stmt->bindparam(":permit",$permit);
$stmt->execute();
return $stmt;
}
catch(PDOException $e)
{
echo $e->getMessage();
}
}
I'm posting this as a community wiki answer, since there shouldn't be any rep from this, nor do I want rep from it; given an answer that can't determine which one is missing.
It's the one for $stmt->bindparam(":address",$address); that is missing in the VALUES().
Also make sure that all variables do contain value.
PHP's error reporting will be of help:
http://php.net/manual/en/function.error-reporting.php
Side note: Using a code editor that automatically finds matching words when double-clicked and using the same naming convention would have helped you greatly.
One (free) of which that has option, is Notepad++.
Your sql statement is inconsistent: the table columns and the values
to insert don't correspond. For example, in a curr_position field
you are trying to insert a value of :joind, etc.
Also, in terms of number, the columns and the values to insert don't
coincide: 19 values to insert in 20 fields.
Recommendations:
My recommendation would be to always use column names for the marker names. Then you know exactly to which markers you are inserting the corresponding values.
NB: Markers: "...VALUES (:marker1, :marker2, ...);".
You should also define the type of input parameteres that you are binding. Example:
$stmt->bindparam(":age", $age, PDO::PARAM_INT);
Try to maintain some consistency between the function parameters and the field names, if it's possible and... makes sense.
My code proposal would look like this:
<?php
public function register(
$userName
, $birth
, $gender
, $image
, $jobTitle
, $currPosition
, $telephone
, $department
, $joiningDate
, $userEmail
, $userPass
, $boxNumber
, $residence
, $nssfNumber
, $bankAccount
, $passportNumber
, $homeDistrict
, $village
, $nationality
, $workPermit
) {
try {
$newUserPassword = password_hash($userPass, PASSWORD_DEFAULT);
$stmt = $this->conn->prepare('INSERT INTO users (
user_name,
birth,
gender,
image,
job_title,
curr_position,
telephone,
department,
joining_date,
user_email,
user_pass,
box_number,
residence,
nssf_number,
bank_account,
passport_number,
home_district,
village,
nationality,
work_permit
) VALUES (
:user_name,
:birth,
:gender,
:image,
:job_title,
:curr_position,
:telephone,
:department,
:joining_date,
:user_email,
:user_pass,
:box_number,
:residence,
:nssf_number,
:bank_account,
:passport_number,
:home_district,
:village,
:nationality,
:work_permit
)');
$stmt->bindparam(":user_name", $userName, PDO::PARAM_STR);
$stmt->bindparam(":birth", $birth, PDO::PARAM_INT);
$stmt->bindparam(":gender", $gender, PDO::PARAM_STR);
$stmt->bindparam(":image", $image, PDO::PARAM_STR);
$stmt->bindparam(":job_title", $jobTitle, PDO::PARAM_STR);
$stmt->bindparam(":curr_position", $currPosition, PDO::PARAM_STR);
$stmt->bindparam(":telephone", $telephone, PDO::PARAM_STR);
$stmt->bindparam(":department", $department, PDO::PARAM_STR);
$stmt->bindparam(":joining_date", $joiningDate, PDO::PARAM_STR);
$stmt->bindparam(":user_email", $userEmail, PDO::PARAM_STR);
$stmt->bindparam(":user_pass", $newUserPassword, PDO::PARAM_STR);
$stmt->bindparam(":box_number", $boxNumber, PDO::PARAM_INT);
$stmt->bindparam(":residence", $residence, PDO::PARAM_STR);
$stmt->bindparam(":nssf_number", $nssfNumber, PDO::PARAM_INT);
$stmt->bindparam(":bank_account", $bankAccount, PDO::PARAM_STR);
$stmt->bindparam(":passport_number", $passportNumber, PDO::PARAM_STR);
$stmt->bindparam(":home_district", $homeDistrict, PDO::PARAM_STR);
$stmt->bindparam(":village", $village, PDO::PARAM_STR);
$stmt->bindparam(":nationality", $nationality, PDO::PARAM_STR);
$stmt->bindparam(":work_permit", $workPermit, PDO::PARAM_STR);
$stmt->execute();
return $stmt;
} catch (PDOException $e) {
echo $e->getMessage();
}
}
Good luck!
Thank you all for your efforts and input i figured out the problem actually was this one:
$stmt->bindParam("userPass", $newUserPassword, PDO::PARAM_STR);
which had to be changed to this:
$stmt->bindParam("userPass", $userPass, PDO::PARAM_STR);
I was trying to use a parameter that i had not defined all because i di this:
$newUserPassword = password_hash($userPass, PASSWORD_DEFAULT);
So I thought of replacing it in the bindParameters....Hope it helps other!

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);

Reversing AES_ENCRYPT Difficulties

I am consistently receiving null whenever I try to reverse the cipher text that I store in a MySQL database through PHP.
The PHP code used to insert the data:
public function insertChildren($employeeID, $empData, $key, $childName, $childBirth, $childGender, $childSSN, $isStep, $isFoster, $isStudent, $isHandicap, $address) {
$conn = $this->connect('insurance');
$insertChildren = $conn->prepare('INSERT INTO dependent_children (emp_id, ssn, name, dob, gender, handicap, student, foster, step, address) VALUES (:emp_id, AES_ENCRYPT(:ssn, AES_ENCRYPT(:key, UNHEX(sha1(:empData)))), :name, :dob, :gender, :handicap, :student, :foster, :step, :address)');
$insertChildren->bindParam(":emp_id", $employeeID, PDO::PARAM_INT);
$insertChildren->bindParam(":name", $childName, PDO::PARAM_STR);
$insertChildren->bindParam(':dob', $childBirth, PDO::PARAM_STR);
$insertChildren->bindParam(':empData', $empData, PDO::PARAM_STR);
$insertChildren->bindParam(':gender', $childGender, PDO::PARAM_STR);
$insertChildren->bindParam(':key', $key);
$insertChildren->bindParam(':ssn', $childSSN, PDO::PARAM_LOB);
$insertChildren->bindParam(':handicap', $isHandicap, PDO::PARAM_STR);
$insertChildren->bindParam(':student', $isStudent, PDO::PARAM_STR);
$insertChildren->bindParam(':foster', $isFoster, PDO::PARAM_STR);
$insertChildren->bindParam(':step', $isStep, PDO::PARAM_STR);
$insertChildren->bindParam(':address', $address, PDO::PARAM_STR);
$insertChildren->execute();
}
The SQL query that I thought would reverse it:
SELECT CAST(AES_DECRYPT(ssn, AES_DECRYPT('/ same random hexadecimal key bound in the php statement / ', unhex(sha1('1234')))) AS CHAR(50)) from dependent_children
Please note 1234 is the value that should be bound to the empData field in the PHP. I thought the latter query would correctly decrypt the first, but such is the case. Instead, I receive null. I am sure it is something simple, but I have not been able to locate the error source. Thanks so much!

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);

How to get values from autoincrements from a table and use it in relation to another table?

I am new to php en msq sql en made a form to add to a database.I have 3 tables with 3 autoincrements,if it could i would have had 5. I wonder if its possible to get an autoincrement value from a table and apply it to another. I have betaling and adresgegevens increments which i want to be linked with klantgegevens, but if i try to add my form to my database i get this.
Warning: PDOStatement::execute() [pdostatement.execute]: SQLSTATE[HY093]: Invalid parameter number: parameter was not defined in.
Furthermore i used 3 sql statements if i drop the 3th i can insert the form without a problem but thats not what i want.
Any other solutions are very welcome.
this is my php code
<?php
if(isset($_POST["submit3"])){
$verbinding = new PDO("mysql:host=localhost;port=3307;dbname=ziggo2","root","usbw");
$sql1="
INSERT INTO betaling (order_id,rekeningnr,basispakket,voordeel)
VALUES (:order_id,:rekeningnr,:basispakket,:voordeel);
";
$statement = $verbinding ->prepare($sql1);
$statement->bindValue(":order_id", '', PDO::PARAM_STR);
$statement->bindValue(":rekeningnr", $_SESSION['rekeningnr'], PDO::PARAM_STR);
$statement->bindValue(":basispakket", '50', PDO::PARAM_STR);
$statement->bindValue(":voordeel", $_SESSION['voordeel'], PDO::PARAM_STR);
$statement->execute();
$count1 = $statement->rowCount();
$sql2="
INSERT INTO adresgegevens (adres_id,postcode,huisnr,straat,plaats,datum)
VALUES(:adres_id,:postcode,:huisnr,:straat,:plaats,:datum);
";
$statement = $verbinding ->prepare($sql2);
$statement->bindValue(":adres_id", '', PDO::PARAM_STR);
$statement->bindValue(":postcode", $_SESSION['postcode'], PDO::PARAM_STR);
$statement->bindValue(":huisnr", $_SESSION['huisnr'], PDO::PARAM_STR);
$statement->bindValue(":straat", $_SESSION['straat'], PDO::PARAM_STR);
$statement->bindValue(":plaats", $_SESSION['plaats'], PDO::PARAM_STR);
$statement->bindValue(":datum", '', PDO::PARAM_STR);
$statement->execute();
$count2 = $statement->rowCount();
$sql3="
JOIN adresgegevens a on a.adres_id = k.adres_id JOIN klantgegevens k on k.order_id = b.order_id JOIN betaling where klantgegevens k = k.klantnr
INSERT INTO klantgegevens(klantnr,adres_id,order_idgeslacht,voorletters,tussenvoegsel,achternaam,gebdat,e-mail,telnr,producten)
VALUES (:klantnr,:adres_id,:order_id,:geslacht,:voorletters,:tussenvoegsel,:achternaam,:gebdat,:e-mail,:telnr,:producten);
";
$statement = $verbinding ->prepare($sql3);
$statement->bindValue(":klantnr", '', PDO::PARAM_STR);
$statement->bindValue(":adres_id", '' , PDO::PARAM_STR);
$statement->bindValue(":order_id", '', PDO::PARAM_STR);
$statement->bindValue(":geslacht", $_SESSION['geslacht'], PDO::PARAM_STR);
$statement->bindValue(":voorletters", $_SESSION['voorletters'], PDO::PARAM_STR);
$statement->bindValue(":tussenvoegsel", $_SESSION['tussenvoegsel'], PDO::PARAM_STR);
$statement->bindValue(":achternaam", $_SESSION['achternaam'], PDO::PARAM_STR);
$statement->bindValue(":gebdat", $_SESSION['gebdat'], PDO::PARAM_STR);
$statement->bindValue(":e-mail", $_SESSION['e-mail'], PDO::PARAM_STR);
$statement->bindValue(":telnr", $_SESSION['telnr'], PDO::PARAM_STR);
$statement->bindValue(":producten", $_SESSION['producten'], PDO::PARAM_STR);
$statement->execute();
$count3 = $statement->rowCount();
// SET #lastid = LAST_INSERT_ID();
if($count1 == 1 AND $count2 == 1 AND $count3 == 1){
print("Er is $count1 rij succesvol toegevoegd.");
}
else{
print("OOps er is wat fout gegaan");
}
//if strlen( $count => 1){
// print("U heeft" . $count . "regel toegevoegd");
//}
}
?>
The trick you need is the MySQL function LAST_INSERT_ID().
http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_last-insert-id
This evaluates to the most recently used autoincrement id.
You can retrieve it into your client (php) program using the query
SELECT LAST_INSERT_ID() AS last_id
The function PDO::lastInsertId() is a shortcut for this.
You can also use it in a sequence of INSERT or UPDATE statements. For example:
INSERT INTO name (surname, given, title) VALUES ( :sur, :giv, :title )
INSERT INTO address (name_id, street, city) VALUES (LAST_INSERT_ID(), :street, :city)
Why does this work, even on a busy database with many connections? Because MySQL maintains values for LAST_INSERT_ID() in the context for each distinct connection.

Categories