PDO: Integrity constraint violation (UPDATE TABLE) - php

First Table:
CREATE TABLE Portfolio_Categories
(
cat_id int(11) NOT NULL,
cat_title varchar(255) NOT NULL,
cat_dir varchar(255) NOT NULL
)
ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1;
Second Table:
CREATE TABLE Portfolio_Images
(
img_id int(11) NOT NULL,
cat_id int(11) NOT NULL,
img varchar(255) NOT NULL,
img_title varchar(255) DEFAULT NULL
)
ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=latin1 COMMENT='Table to store the Portfolio Images';
Constraints:
ALTER TABLE Portfolio_Categories
ADD PRIMARY KEY (cat_id);
ALTER TABLE Portfolio_Images
ADD PRIMARY KEY (img_id), ADD KEY cat_id (cat_id), ADD KEY img_id (img_id);
ALTER TABLE Portfolio_Images ADD CONSTRAINT cat_id FOREIGN KEY
(cat_id) REFERENCES Portfolio_Categories (cat_id);
My PHP Code:
$query = "UPDATE
Portfolio_Images
SET
Portfolio_Images.img = :new_img,
Portfolio_Images.img_title = :new_tit,
Portfolio_Images.cat_id =
(SELECT t_cat.cat_id FROM (SELECT * FROM Portfolio_Categories) AS t_cat WHERE t_cat.cat_title = :new_cat)
WHERE
Portfolio_Images.img = :old_img;";
$stmt = $_MySQLConn->prepare($query);
$stmt->bindParam(':new_img', $new_img);
$stmt->bindParam(':new_tit', $new_tit);
$stmt->bindParam(':new_cat', $new_cat);
$stmt->bindParam(':old_img', $old_img);
if($stmt->execute())
{
$return_value = array('success'=>true,
'new_img:'=>$new_img,
'new_tit'=>$new_tit,
'new_cat'=>$new_cat,
'old_img'=>$old_img);
}
else
{
$return_value = array('success'=>false,'error_code'=>'Could not execute query');
}
What should it do:
It should update my table without any error (as it does if I run the statement directly)
What does it do:
PHP shows me this error message:
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or
update a child row: a foreign key constraint fails
(1_new.Portfolio_Images, CONSTRAINT cat_id FOREIGN KEY
(cat_id) REFERENCES Portfolio_Categories (cat_id))

This means that you are inserting a row in Portfolio_Images where the value in Portfolio_Images.cat_id does not exist in Portfolio_Categories.cat_id.
In other words, if in Portfolio_Categories.cat_id you only have the values 1, 2, 4 you can only insert in Portfolio_Images.cat_id the values 1, 2 or 4.

Related

Get the value when a MySQL constraint fails

Assuming I am inserting rows in a MySQL table with a constraint
CREATE TABLE `parent` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
;
CREATE TABLE `child` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`id_parent` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`id`),
INDEX `FK_parent_child` (`id_parent`),
CONSTRAINT `FK_parent_child` FOREIGN KEY (`id_parent`) REFERENCES `parent` (`id`),
)
ENGINE=InnoDB
;
Then when I do an insert in the child table without the entry in the parent table:
INSERT INTO child (id, id_parent) VALUES (1, 1);
I get the following error:
Cannot add or update a child row: a foreign key constraint fails (`...`.`child`, CONSTRAINT `FK_parent_child` FOREIGN KEY (`id_parent`) REFERENCES `parent` (`id`))`
But is there a way to retrieve the value of the insert-failed row, aka 1 here? Because when I insert thousands of rows at the same time, it would be very useful to get the failed one.
I would like a fully-MySQL way, but a PHP way would work too in my case.

cannot add or update a child row a foreign key constraint fails mysql Error Number: 1452

the berita_ukm table
CREATE TABLE `berita_ukm` (
`id_berita` int(11) NOT NULL AUTO_INCREMENT,
`id_admin` int(11) DEFAULT NULL,
`judul_berita` varchar(45) DEFAULT NULL,
`content` varchar(225) DEFAULT NULL,
`tanggal` date DEFAULT NULL,
PRIMARY KEY (`id_berita`),
FOREIGN KEY (`id_admin`) REFERENCES `admin` (`id_admin`)
)
admin table
CREATE TABLE `berita_ukm` (
`id_admin` int(11) NOT NULL AUTO_INCREMENT,
`name` int(11) DEFAULT NULL,
PRIMARY KEY (`id_admin`),
)
and i found error like this
Error Number: 1452
Cannot add or update a child row: a foreign key constraint fails
(`tugas_akhir`.`berita_ukm`, CONSTRAINT `berita_ukm_ibfk_1`
FOREIGN KEY (`id_admin`) REFERENCES `admin` (`id_admin`))
INSERT INTO `berita_ukm`
(`id_berita`, `tanggal`, `judul_berita`, `content`)
VALUES ('34', '3/25/2014', 'putri', 'nfdn')
please help me what to do. thank you
I guess you misplaced the col names in your insert("id_berita" in place of "id_admin" ), since col "id_berita" is auto increment, you don't need to provide value for that col during insert.
INSERT INTO `berita_ukm`
(`id_admin`, `tanggal`, `judul_berita`, `content`)
VALUES ('34', '3/25/2014', 'putri', 'nfdn')

Programmatically display column names violating MySQL unique constraint with PHP

When MySQL returns 23000 error code, it means that the update/insert query has triggered integrity constraint violation. However, the error, e.g.
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '22-offline-mpu-l' for key 'client_ad'
However, how to tell what are the columns that require unique combination?
The above table schema is:
CREATE TABLE `ad` (
`id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
`client_id` smallint(5) unsigned NOT NULL,
`slug` varchar(100) CHARACTER SET latin1 NOT NULL DEFAULT '',
`name` varchar(100) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`status` tinyint(3) unsigned NOT NULL,
`width` smallint(5) unsigned NOT NULL,
`height` smallint(5) unsigned NOT NULL,
`code` varchar(2040) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
UNIQUE KEY `client_ad` (`client_id`,`slug`),
CONSTRAINT `ad_ibfk_1` FOREIGN KEY (`client_id`) REFERENCES `client` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1746 DEFAULT CHARSET=utf8;
This is a proposal, rather than a definitive solution:
try {
// Query
} catch (\PDOException $e) {
if ($e->getCode() === '23000') {
// SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '22-offline-mpu-l' for key 'client_ad'
preg_match('/(?<=\')[^\']*(?=\'[^\']*$)/', $e->getMessage(), $match);
$columns = $this->db->prepare("
SELECT
`f1`.`name`
FROM
`information_schema`.`innodb_sys_tables` `t1`
INNER JOIN
`information_schema`.`innodb_sys_indexes` `i1` USING (`table_id`)
INNER JOIN
`information_schema`.`innodb_sys_fields` `f1` USING (`index_id`)
WHERE
`t1`.`schema` = DATABASE() AND
`t1`.`name` = :table_name AND
`i1`.`name` = :key_name AND
`i1`.`type` IN (2, 3)
ORDER BY
`f1`.`pos`;
")
->execute(['table_name' => static::$table_name, 'key_name' => $match[0]])
->fetchAll(\PDO::FETCH_COLUMN);
// $columns contains names of the columns that make up the index with the integrity constraint.
} else {
throw $e;
}
}
This uses regular expression to match the key name, then looks up the associated columns with the database, table and key name combination. innodb_sys_indexes.type 2 and 3 are the only (http://dev.mysql.com/doc/refman/5.6/en/innodb-sys-indexes-table.html) keys that (apply to tables) require unique values across the table.
It looks like the problem is with the foreign key referencing the client table, so I would do:
SHOW INDEXES FROM client WHERE Non_unique = 0;
and look at the columns you get back.
http://dev.mysql.com/doc/refman/5.0/en/show-index.html

Foreign key constraint fails in transaction

I'm developing a web-based application with PHP/MySQL + Yii Framework. The problem occurs as a constraint check error in a transaction.
I have the following tables:
User
CREATE TABLE IF NOT EXISTS `User` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(64) DEFAULT NULL,
`surname` varchar(64) DEFAULT NULL,
`email` varchar(128) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`creation_date` datetime DEFAULT NULL,
`last_login_date` datetime DEFAULT NULL,
`status` tinyint(1) DEFAULT '0',
`level` tinyint(1) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=40 ;
CandidateInfo
CREATE TABLE IF NOT EXISTS `CandidateInfo` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`candidate_status_id` int(11) DEFAULT NULL,
`name` varchar(64) DEFAULT NULL,
`surname` varchar(64) DEFAULT NULL,
`email` varchar(128) DEFAULT NULL,
`gender` tinyint(1) DEFAULT '0',
`date_of_birth` datetime DEFAULT NULL,
`home_phone` varchar(20) DEFAULT NULL,
`mobile_phone` varchar(20) DEFAULT NULL,
`creation_date` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`rating` tinyint(1) DEFAULT '0',
`location` varchar(100)DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `FK_candidateinfo_user` (`id`),
KEY `FK_candidateinfo_candidatestatus` (`candidate_status_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=26 ;
Basically I'm trying to add a new row to User table, and then use the insert id to add a new row to the CandidateInfo table (user_id column)
The php code is as
$transaction = Yii::app()->db->beginTransaction();
try {
$user->save();
$candidate->setAttribute('user_id', $user->id);
$candidate->save();
$transaction->commit();
} catch (Exception $e) {
$transaction->rollBack();
var_dump($e->getMessage());
}
The error is:
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`origo`.`CandidateInfo`, CONSTRAINT `FK_candidateinfo_user` FOREIGN KEY (`id`) REFERENCES `User` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION). The SQL statement executed was: INSERT INTO `CandidateInfo` (`gender`, `rating`, `name`, `surname`, `email`, `date_of_birth`, `home_phone`, `mobile_phone`, `user_id`) VALUES (:yp0, :yp1, :yp2, :yp3, :yp4, :yp5, :yp6, :yp7, :yp8)
When i check the mysql query logs, i see that it takes the right user_id for the INSERT statement for CandidateInfo table. But fails with the above error. From my understanding, it is supposed to work, but may be i am mistaken and this is not the way transactions are meant to work.
Both tables are InnoDB.
Thanks in advance.
Edit:
Sorry forgot to paste the FK relations.
ALTER TABLE `CandidateInfo`
ADD CONSTRAINT `FK_candidateinfo_candidatestatus` FOREIGN KEY (`candidate_status_id`) REFERENCES `CandidateStatus` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
ADD CONSTRAINT `FK_candidateinfo_user` FOREIGN KEY (`id`) REFERENCES `User` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;
ALTER TABLE `CandidateInfo`
ADD CONSTRAINT `FK_candidateinfo_candidatestatus` FOREIGN KEY (`candidate_status_id`) REFERENCES `CandidateStatus` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
ADD CONSTRAINT `FK_candidateinfo_user` FOREIGN KEY (`id`) REFERENCES `User` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;
should be
ALTER TABLE `CandidateInfo`
ADD CONSTRAINT `FK_candidateinfo_candidatestatus` FOREIGN KEY (`candidate_status_id`) REFERENCES `CandidateStatus` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
ADD CONSTRAINT `FK_candidateinfo_user` FOREIGN KEY (`user_id`) REFERENCES `User` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;
you've got id references id in yours.
Your error stack:
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (origo.CandidateInfo, CONSTRAINT FK_candidateinfo_user FOREIGN KEY (id) REFERENCES User (id) ON DELETE NO ACTION ON UPDATE NO ACTION).
The SQL statement executed was:
INSERT INTO `CandidateInfo`
( `gender`, `rating`, `name`, `surname`, `email`,
`date_of_birth`, `home_phone`, `mobile_phone`, `user_id`
)
VALUES ( :yp0, :yp1, :yp2, :yp3, :yp4, :yp5, :yp6, :yp7, :yp8 )
Your CandidateInfo table defines id field as auto_increment primary key field and a foreign key as well.
And your insert statement does not include id, read from its parent user table.
And hence on insert a new id value is generated for candidateinfo table and applied.
Which intern failed as it did not match any of the primary key id value of the parent user table.
And hence is the error.
Note:
In a child table if your are referring a pk field of a master as a foreign key field,
you should not apply auto_increment for it but just refer.
And looking closely the candidateinfo structure, I feel that you might want to map use_id to user.id field. Making that change, with proper foreign key definition used, would resolve your problem.

Insertion Failed:Cannot add or update a child row: a foreign key constraint fails

I have two tables- users and language with a foreign key link of their primary key 'id'.
I have checked that the type is innoDB for the tables. I have delete- restrict and update -cascade.
This insert query, inserts it into the language table: (it can be more than one row which is added as the form has dynamic clickevent button)
if(empty($_SESSION['user_id'])) { // user not logged in; redirect to somewhere else }
$sql_insert = "INSERT into `language`
(`native`,`other`,`other_list`,`other_read`, `other_spokint`
,`other_spokprod`,`other_writ` )
VALUES
('$native','$other','$other_list','$other_read','$other_spokint','$other_spokprod',
'$other_writ') ";
mysql_query($sql_insert,$link) or die("Insertion Failed:" . mysql_error());
}
This is the full error:
Insertion Failed:Cannot add or update a child row: a foreign key constraint fails
(`members`.`language`, CONSTRAINT `language_ibfk_1` FOREIGN KEY (`id`)
REFERENCES `users` (`id`))
Any help would be appreciated!
Table structure for table language:
CREATE TABLE IF NOT EXISTS `language` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`native` varchar(30) NOT NULL,
`other` varchar(30) NOT NULL,
`other_list` varchar(9) NOT NULL,
`other_read` varchar(9) NOT NULL,
`other_spokint` varchar(9) NOT NULL,
`other_spokprod` varchar(9) NOT NULL,
`other_writ` varchar(9) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
RELATIONS FOR TABLE `language`:
`id`
`users` -> `id`
You have to use a structure like this:
create table users (
id int not null auto_increment,
<additional fields>,
primary key (id)
) ENGINE=InnoDB;
create table language(
id int not null auto_increment,
user_id int not null,
<additional fields>,
primary key (id),
foreign key (user_id) references users(id) on delete restrict on update cascade
) ENGINE=InnoDB;

Categories