Yesterday i had this topic with "pdo inserting and updating. Now here is the following
Warning: PDOStatement::execute() [pdostatement.execute]: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in on line 148
And this is my code.
$sth = $db->prepare(
'INSERT INTO track (`rsname`, `overallranknow`, `overalllevelnow`, `overallxpnow` )' .
'VALUES (:name, :Overalln, :Overall1, :Overall2) '.
'ON DUPLICATE KEY UPDATE ' .
"rsname = :name" .
"overallranknow = :Overalln" .
"overalllevelnow = :Overall1" .
"overallxpnow = :Overall2"
);
$sth->bindValue(':name', $name, PDO::PARAM_STR);
$sth->bindValue(':Overalln', $Overalln, PDO::PARAM_INT);
$sth->bindValue(':Overall1', $Overall[1], PDO::PARAM_INT);
$sth->bindValue(':Overall2', $Overall[2], PDO::PARAM_INT);
$sth->execute();
The error says my execute line is the wrong 1. I have tried it with a array and i still got it then. I hope maybe knows what i mean.
~Kev (bad english = sorry)
From the PDO::prepare manual;
You must include a unique parameter marker for each value you wish to pass in to the statement when you call PDOStatement::execute(). You cannot use a named parameter marker of the same name twice in a prepared statement.
That (sadly) means that you'll have to duplicate your bindings with secondary names to use the same value twice in a query. Not pretty, something like;
$sth = $db->prepare(
'INSERT INTO track (`rsname`, `overallranknow`, `overalllevelnow`, `overallxpnow` )' .
'VALUES (:name, :Overalln, :Overall1, :Overall2) '.
'ON DUPLICATE KEY UPDATE ' .
"rsname = :name_2" .
"overallranknow = :Overalln_2" .
"overalllevelnow = :Overall1_2" .
"overallxpnow = :Overall2_2"
);
$sth->bindValue(':name', $name, PDO::PARAM_STR);
$sth->bindValue(':name_2', $name, PDO::PARAM_STR);
$sth->bindValue(':Overalln', $Overalln, PDO::PARAM_INT);
$sth->bindValue(':Overalln_2', $Overalln, PDO::PARAM_INT);
$sth->bindValue(':Overall1', $Overall[1], PDO::PARAM_INT);
$sth->bindValue(':Overall1_2', $Overall[1], PDO::PARAM_INT);
$sth->bindValue(':Overall2', $Overall[2], PDO::PARAM_INT);
$sth->bindValue(':Overall2_2', $Overall[2], PDO::PARAM_INT);
$sth->execute();
EDIT: Since MySQL allows for the VALUES keyword in ON DUPLICATE KEY to not have to repeat the parameters, you'd be better off using #YourCommonSense's answer for this exact case.
INSERT INTO track (rsname, overallranknow, overalllevelnow, overallxpnow)
VALUES (:name, :Overalln, :Overall1, :Overall2)
ON DUPLICATE KEY UPDATE
rsname = values(rsname),
overallranknow = values(overallranknow),
overalllevelnow = values(overalllevelnow),
overallxpnow = values(overallxpnow)
it have to be.
Related
I am trying to update a database that tracks a household. It keeps the household head as a client in a separate table, but uses their ID as a foreign key in the household table. I need to be able to add multiple people in a household. I tried using just an UPDATE statement, but it only replaced the data when I tried to add multiple people at once. I am trying to do this not using DELETE and INSERT statements for fear of losing information. For added information, this is all manipulated by a PHP Fat-Free Website because my school teaches it.
function editHousehold($id, $name, $age, $gender){
$id = $this->getLastId();
$sql= "UPDATE Household SET `name`=:name, age=:age, gender=:gender WHERE
Guests_ClientId=:Guests_ClientId";
$statement = $this->dbh->prepare($sql);
$statement->bindParam(':name', $name, PDO::PARAM_STR);
$statement->bindParam(':age', $age, PDO::PARAM_STR);
$statement->bindParam(':gender', $gender, PDO::PARAM_STR);
$statement->bindParam(':Guests_ClientId', $id, PDO::PARAM_INT);
$statement->execute();
}
Vs.
function editNeeds($id,$resource,$date, $amount, $voucher, $checkNum){
$sql = "DELETE FROM Needs WHERE Guests_ClientId = $id";
$statement = $this->dbh->prepare($sql);
$statement->execute();
$id = $this->getLastId();
$sql= "INSERT INTO Needs (resource, visitDate, amount, voucher, checkNum, Guests_ClientId)
VALUES (:resource, :date , :amount, :voucher, :checkNum, $id)";
$statement = $this->dbh->prepare($sql);
$statement->bindParam(':resource', $resource, PDO::PARAM_STR);
$statement->bindParam(':amount', $amount, PDO::PARAM_STR);
$statement->bindParam(':voucher', $voucher, PDO::PARAM_STR);
$statement->bindParam(':checkNum', $checkNum, PDO::PARAM_STR);
$statement->bindParam(':date', $date, PDO::PARAM_STR);
$statement->execute();
}
/**
* edit households, removes the old and replaces witha new set of values
* #param $id
* #param $name
* #param $age
* #param $gender
*/
function editHousehold($id, $name, $age, $gender){
$sql = "DELETE FROM Household WHERE Guests_ClientId = $id";
$statement = $this->dbh->prepare($sql);
$statement->execute();
$id = $this->getLastId();
$sql= "INSERT INTO Household (name, age, gender,Guests_ClientId)
VALUES (:name,:age,:gender,$id)";
$statement = $this->dbh->prepare($sql);
$statement->bindParam(':name', $name, PDO::PARAM_STR);
$statement->bindParam(':age', $age, PDO::PARAM_STR);
$statement->bindParam(':gender', $gender, PDO::PARAM_STR);
$statement->execute();
}
I think you are looking for an "either insert new entry or update if the primary key exists" type of statement. This is called "upsert", and MySQL provides it in the form of INSERT ... ON DUPLICATE KEY UPDATE.
It will insert new entries, unless the primary key of one of the entries to insert already exists. If so, it will instead update the existing entry.
Getting these errors on lines 33 and 54 (my statement execute lines for the two queries), but not sure why. Looks like my bound variables all line up. Any thoughts?
Warning: PDOStatement::execute() [pdostatement.execute]: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens... on line 33
Warning: PDOStatement::execute() [pdostatement.execute]: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens... on line 54
Also, I have concerns as to whether this will work and the binding will accept the $SID2 variable with correct value, but can't tell until above errors are resolved:
$SID = $dbh->lastInsertId();
$SID2 = $SID;
Here is the relevant code:
$dbh = new pdo('mysql:host='.$hostName.';dbname='.$dataBaseName, $user, $pass);
if(isset($_POST ['submit'])){
$user_ID = get_current_user_id();
$sql = "INSERT INTO stories(ID,
category,
genre,
rating,
story_name,
active) VALUES (
:ID,
:genre,
:rating,
:story_name,
:active)";
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':ID', $user_ID, PDO::PARAM_STR);
$stmt->bindParam(':category', $_POST['category'], PDO::PARAM_STR);
$stmt->bindParam(':genre', $_POST['genre'], PDO::PARAM_STR);
$stmt->bindParam(':rating', $_POST['rating'], PDO::PARAM_STR);
$stmt->bindParam(':story_name', $_POST['story_name'], PDO::PARAM_STR);
$stmt->bindParam(':active', $a = 0, PDO::PARAM_STR);
$stmt->execute(); //line 33---error line
$SID = $dbh->lastInsertId();
$SID2 = $SID;
$sql2 = "INSERT INTO writing(ID,
SID,
text,
position,
approved) VALUES (
:ID,
:SID,
:text,
:position,
:approved)";
$stmt2 = $dbh->prepare($sql2);
$stmt->bindParam(':ID', $user_ID, PDO::PARAM_STR);
$stmt->bindParam(':SID', $SID2, PDO::PARAM_STR);
$stmt->bindParam(':text', $_POST['text'], PDO::PARAM_STR);
$stmt->bindParam(':position', $b = 0, PDO::PARAM_STR);
$stmt->bindParam(':approved', $c = 0, PDO::PARAM_STR);
$stmt->execute(); //line 54--error line
In first sql is one value missing
VALUES (
:ID,
:category, ---> inserted
:genre,
:rating,
:story_name,
:active)";
And the second one shuld be stmt2 instead of stmt i think (also the bind`s)
in your sql2 you bind to the wrong PDO object. You used $stmt->bindParam() instead of $stmt2->bindParam();
Just replact $stmt to $stmt2 in your $sql2 query.
My Script needs to update the table if the name is already in there. But it is not doing it.
This is my code that i'm using
$sth = $db->prepare(
'INSERT INTO track (rsname, overallranknow, overalllevelnow, overallxpnow)
VALUES (:name, :Overalln, :Overall1, :Overall2)
ON DUPLICATE KEY UPDATE
rsname = values(rsname),
overallranknow = values(overallranknow),
overalllevelnow = values(overalllevelnow),
overallxpnow = values(overallxpnow)'
);
$sth->bindValue(':name', $name, PDO::PARAM_STR);
$sth->bindValue(':Overalln', $Overalln, PDO::PARAM_INT);
$sth->bindValue(':Overall1', $Overall[1], PDO::PARAM_INT);
$sth->bindValue(':Overall2', $Overall[2], PDO::PARAM_INT);
$sth->execute();
It should only update when the name is already there. I dont know mutch about PDO so thats why i'm asking so mutch about it.
~Kev (bad english = sorry)
Someone who taught you this query, didn't tell you that you need an unique key for it to work.
Hi i have a question about mysql
this is my query:
$geboortedatum = $_POST['dag'].'-'.$_POST['maand'].'-'.$_POST['jaar'];
$geboortedatum1 = $_POST['dag1'].'-'.$_POST['maand1'].'-'.$_POST['jaar1'];
try{
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "
INSERT INTO clienten
(client_voornaam,
client_achternaam,
client_geboortedatum,
client_geslacht,
client_adres,
client_postcode,
client_woonplaats,
client_contactpersoon,
client_diagnose,
datun_aanmaak)
VALUES (:voornaam,
:achternaam.
:geboortedatum,
:geslacht,
:adres,
:postcode,
:woonplaats,
:contactpersoon,
:diagnose,
:datumaanmaak)
INSERT INTO verzorgers(
wat_is_verzorger,
voornaam_verzorger,
achternaam_verzorger,
geboortedatum_verzorger,
email_verzorger,
geslacht_verzorger,
adres_verzorger,
postcode_verzorger,
woontplaats_verzorger,
tel1_verzorger,
tel2_verzorger,
datum_aanmaak
)
VALUES(
:watisverz
:voornaamverz,
:achternaamverz,
:geboortedatumverz,
:emailverz,
:geslachtverz:
:adresverz,
:postcodeverz,
:woonplaatsverz,
:tel1verz,
:tel2verz,
:datumaanmaak
)
";
$stmt = $db->prepare($sql);
$stmt->bindParam(':voornaam', $_POST['voornaam'], PDO::PARAM_STR);
$stmt->bindParam(':achternaam', $_POST['achternaam'], PDO::PARAM_STR);
$stmt->bindParam(':geboortedatum', $geboortedatum, PDO::PARAM_INT);
$stmt->bindParam(':geslacht', $_POST['geslacht'], PDO::PARAM_STR);
$stmt->bindParam(':adres', $_POST['adres'], PDO::PARAM_STR);
$stmt->bindParam(':postcode', $_POST['postcode'], PDO::PARAM_INT);
$stmt->bindParam(':woonplaats', $_POST['woonplaats'], PDO::PARAM_STR);
$stmt->bindParam(':contactpersoon', $_POST['contactpersoon'], PDO::PARAM_STR);
$stmt->bindParam(':diagnose', $_POST['diagnose'], PDO::PARAM_INT);
$stmt->bindParam(':datumaanmaak', $_POST['datum_toetreding'], PDO::PARAM_INT);
$stmt->execute();
}
catch(PDOException $e)
{
echo '<pre>';
echo 'Regel: '.$e->getLine().'<br>';
echo 'Bestand: '.$e->getFile().'<br>';
echo 'Foutmelding: '.$e->getMessage();
echo '</pre>';
} ?>
Now when the client and verzorger are created, they both get an unique ID.
Client had a column that stores the verzorger ID associated and vica versa.
Is it possible to make a query that also directly stores the IDs created?
EDIT:
ok maybe to difficult, maybe an answer to get only the client id in verzorger?:)
How about something like this (TableAID and TableBID are both AUTO_INCREMENT columns):
INSERT INTO TableA
(SomeColumn)
VALUES
('Blah');
SET #TableAID = LAST_INSERT_ID();
INSERT INTO TableB
(TableAID, AnotherColumn)
VALUES
(#TableAID,'Foobar');
SET #TableBID = LAST_INSERT_ID();
UPDATE TableA
SET TableBID = #TableBID
WHERE TableAID = #TableAID;
What you can do is create a function that queries against a sequence generator:
create function foo returns int
Begin
Declare nextValue int
Set nextValue = SELECT NEXT VALUE FOR mySequence;
End
return (nextValue);
Which would allow you to pass around the value returned from this sequence and you could know "ahead" of time what the values were going to be.
EDIT
Please understand how concurrency works and use either pessimistic or optimistic locking. While this should be obvious, some feel as though it is necessary to include.
DETAILS
I am doing a single insert for the expiry of a new or renewed licence. The time period for the expiry is 2 years from the insertion date.
If a duplicate is detected, the entry will be updated such that the expiry equals the remaining expiry plus 2 years.
Regarding duplicates, in the example below there should only be one row containing user_id =55 and licence=commercial.
TABLE: licence_expiry
--------------------------------------------------------
| user_id | licence | expiry |
--------------------------------------------------------
| 55 | commercial | 2013-07-04 05:13:48 |
---------------------------------------------------------
user_id (int11), licence (varchan50), expiry (DATETIME)
I think in mysql you would write it something like this (Please note that I haven't checked whether the code works in mysql. )
INSERT INTO `licence_expiry`
(`user_id`, `licence`, `expiry`)
VALUES
(55, commercial, NOW()+ INTERVAL 2 YEAR)
ON DUPLICATE KEY UPDATE
`expiry` = `expiry` + INTERVAL 2 YEAR
QUESTION: How can I do this with PDO? I've written a rough outline of what I think I will use, but I'm not sure what to write for the expiry value for the ON DUPLICATE KEY UPDATE.
$sql = "INSERT INTO $table (user_id, licence, expiry)
VALUES (
:user_id,
:licence,
:expiry)
ON DUPLICATE KEY UPDATE expiry = Something";
try {
$dbh = new PDO('login info here');
$dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':user_id', $userID, PDO::PARAM_INT);
$stmt->bindParam(':licence',$licence, PDO::PARAM_STR);
$stmt->bindParam(':expiry',$expiry, PDO::PARAM_STR);
$stmt->execute();
//$stmt->closeCursor(); //use this instead of $dbh = null if you will continue with another DB function
$dbh = null;
}
catch(PDOException $e)
{
$error=$e->getMessage();
}
Any help is much appreciated.
You can use MySQL's VALUES() function:
In an INSERT ... ON DUPLICATE KEY UPDATE statement, you can use the VALUES(col_name) function in the UPDATE clause to refer to column values from the INSERT portion of the statement. In other words, VALUES(col_name) in the UPDATE clause refers to the value of col_name that would be inserted, had no duplicate-key conflict occurred.
Therefore, in your case:
ON DUPLICATE KEY UPDATE expiry = VALUES(expiry)
Alternatively, you can create a fourth parameter to which you bind $expiry again:
$sql = "INSERT INTO $table (user_id, licence, expiry)
VALUES (
:user_id,
:licence,
:expiry)
ON DUPLICATE KEY UPDATE expiry = :another";
try {
$dbh = new PDO('login info here');
$dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':user_id', $userID , PDO::PARAM_INT);
$stmt->bindParam(':licence', $licence, PDO::PARAM_STR);
$stmt->bindParam(':expiry' , $expiry , PDO::PARAM_STR);
$stmt->bindParam(':another', $expiry , PDO::PARAM_STR);
$stmt->execute();
// etc.
I know you have answer below, but i had same problem and my solution looks quite different but it works for me so if you want to use different statement of using insert in mysql with explicit binding values to columns you can try this code
$sql = "
INSERT INTO
$table
SET
user_id = :user_id,
licence = :licence,
expiry = :expiry
ON DUPLICATE KEY UPDATE
expiry = :expiry
";
$dbh = new PDO('login info here');
$dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$stmt = $dbh->prepare($sql);
$stmt->bindValue('user_id', $userID , PDO::PARAM_INT);
$stmt->bindValue('licence', $licence, PDO::PARAM_STR);
$stmt->bindValue('expiry' , $expiry , PDO::PARAM_STR);