Invalid parameter number for PDO statement - php

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

Related

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

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

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.

using bindParam with PDO

I've been scratching my head over this code for a couple of hours....
Doesn't make sense to me why it doesn't work
$isCorrect =($question->correct_answer == $body->answer) ? 1:0;
// the values are all there.......
// echo $body->question . "\n"; //335
// echo $body->user . "\n"; //51324123
// echo $question->day . "\n"; //0
// echo $isCorrect . "\n"; //0
//but still the below part fails.
$db = getConnection();
$sql = "INSERT INTO `answers` (`id`, `question_id`, `user`, `day`, `is_correct`) VALUES (NULL, ':question', ':user', ':day', :is_correct)";
$stmt = $db->prepare($sql);
$stmt->bindParam(":question_id", $body->question);
$stmt->bindParam(":user", $body->user);
$stmt->bindParam(":day", $question->day, PDO::PARAM_INT);
$stmt->bindParam(":is_correct", $isCorrect, PDO::PARAM_INT);
$stmt->execute();
gives this error:
SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
I'm counting 4 tokens... what am I missing? Obviously I'm doing something wrong.
Try it like this:
$sql = "INSERT INTO `answers` (`id`, `question_id`, `user`, `day`, `is_correct`)
VALUES
--The :variable shouldn't be surrounded by ''--
(NULL, :question, :user, :day, :is_correct)";
$stmt = $db->prepare($sql);
//The values used in $sql should be the same here, so not :question_id but :question
$stmt->bindParam(":question", $body->question);
$stmt->bindParam(":user", $body->user);
$stmt->bindParam(":day", $question->day, PDO::PARAM_INT);
$stmt->bindParam(":is_correct", $isCorrect, PDO::PARAM_INT);
just don't use bindParam with PDO
as well as named parameters. it will save you a ton of headaches
$db = getConnection();
$sql = "INSERT INTO `answers` VALUES (NULL, ?,?,?,?)";
$data = [$body->question,$body->user,$question->day,$isCorrect];
$stmt = $db->prepare($sql)->execute($data);
change :
$stmt->bindParam(":question_id", $body->question);
to:
$stmt->bindParam(":question", $body->question);
You have use in query :question but binding with wrong key(:question_id).
$stmt->bindParam(":question_id", $body->question);
should be
$stmt->bindParam(":question", $body->question);
This is just a little typo.

PDO with bound parameters sql query If statement in update

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

Categories