Reputation: 5504
What i'm trying to do is to insert multiple rows of key/value pairs. The Entries need to be Unique (PrimaryKeys to be specific).
The statement is prepared with the count of values to insert:
$sql = "INSERT INTO `test_values` (`foreignID1`,`value`) VALUES";
for($ix=0;$ix<count($values);$ix++){
if($ix>0){ $sql.= ", ";}
$sql .= "(:parentID,:value$ix)";
}
echo $sql; //INSERT INTO `test_values` (`parentID`,`value`) VALUES (:parentID,:value0), (:parentID,:value1)
then, when preparing the statement i loop the values:
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':parentID',$parentID);
foreach($values as $key => $value){
$valName = ":value$key";
var_dump($valName);
var_dump($value);
$stmt->bindParam($valName,$value);
}
the dumps tell me that every time other values are (correctly) assigned:
string(7) ":value0"
string(14) "one.domain.com"
string(7) ":value1"
string(18) "another.domain.com"
still, i get the SQL error:
Error: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '18-another.domain.com' for key 'PRIMARY'
i definitely know that these entries do not exist. I highly suspect the PDOStatement to bind the same value twice, but i have no idea why it should do so.
[EDIT]: suggested answer implemented, new output:
string(7) ":parent0"
string(14) "18"
string(7) ":value0"
string(14) "one.domain.com"
string(7) ":parent1"
string(14) "18"
string(7) ":value1"
string(18) "another.domain.com"
still the same error.
[EDIT2]: to avoid discussions:
INSERT INTO `test_values` (`parentID`,`value`) VALUES ('18','one.domain.com'),('18','another.domain.com')
applied directly to the database, using phpMyAdmin, works like a charm...what i fear happens to my statement is that the values somehow aren't correctly set, and something like this results:
INSERT INTO `test_values` (`parentID`,`value`) VALUES ('18','another.domain.com'),('18','another.domain.com')
because the constraint always fails on the LAST entry, no matter how many i try to insert.
[EDIT3]:
table structure, as asked:
CREATE TABLE IF NOT EXISTS `test_values` (
`foreignID1` int(11) NOT NULL,
`value` varchar(256) NOT NULL,
PRIMARY KEY (`foreignID1`,`value`)
)
[EDIT4]:
what DOES work is not to use the chained insert, but single ones for each value:
$sql = "INSERT INTO `test_values` (`foreignID1`,`value`) VALUES (:parendID,:value)";
foreach($values as $key => $value){
$stmt = $dbh->prepare($sql);
$stmt->bindParam(":parendID",$parentID);
$stmt->bindParam(":value",$value);
$stmt->execute();
}
....but that's not the actual point of the question.
Upvotes: 0
Views: 126
Reputation: 5504
I finally found the answer myself:
the problem is the foreach loop, since bindParam() doesn't make a copy of the variable, but saves a reference to it. when the statement is executed, the values are read. after the foreach loop is done, the $value variable will hold the last value of the foreach loop.
To get it working, there has to be used either a for loop or the value may not be used:
foreach($values as $key => $value){
$stmt->bindParam(":parendID$key",$parentID);
$stmt->bindParam(":value$key",$values[$key]);
}
Upvotes: 0
Reputation: 10148
As far as I believe, the error which you're receiving indicates that the PRIMARY KEY
s combination already exists in the table. Your table has composite primary keys which means, having
PRIMARY KEY (`foreignID1`,`value`)
you can INSERT
such data
+------------+-------+
| foreignID1 | value | # There are duplicated `foo` values
+------------+-------+ # for column `value` which is ok
| 1 | foo | # because PRIMARY KEY is made of
+------------+-------+ # two columns together,
| 2 | foo | # not each respectively
+------------+-------+
| 3 | bar |
+------------+-------+
while this situation is not possible
+------------+-------+
| foreignID1 | value | # First two entries are
+------------+-------+ # a constraint violation.
| 1 | foo | #
+------------+-------+ # Columns `foreignID1` and `value`
| 1 | foo | # create a single PRIMARY KEY
+------------+-------+ # therefore having the same combination
| 2 | bar | # of values in these columns is impossible
+------------+-------+
Upvotes: 1
Reputation: 34416
Change this -
$sql .= "(:parentID,:value$ix)";
to this -
$sql .= "(:parentID$ix,:value$ix)";
So your parent id gets incremented too.
Upvotes: 1