& quot; Нарушение ограничения целостности: 1062 Duplicate entry & quot; — но нет повторяющихся строк

Я конвертирую приложение из нативных вызовов mysqli в PDO. Ошибка при попытке вставить строку в таблицу с ограничением внешнего ключа.

Замечания: это упрощенный тестовый пример, и его не следует копировать / вставлять в производственную среду.

Информация PHP 5.3, MySQL 5.4

Во-первых, вот таблицы:

CREATE TABLE `z_one` (
`customer_id` int(10) unsigned NOT NULL DEFAULT '0',
`name_last` varchar(255) DEFAULT NULL,
`name_first` varchar(255) DEFAULT NULL,
`dateadded` datetime DEFAULT NULL,
PRIMARY KEY (`customer_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `z_one` VALUES (1,'Khan','Ghengis','2014-12-17 10:43:01');

CREATE TABLE `z_many` (
`order_id` varchar(15) NOT NULL DEFAULT '',
`customer_id` int(10) unsigned DEFAULT NULL,
`dateadded` datetime DEFAULT NULL,
PRIMARY KEY (`order_id`),
KEY `order_index` (`customer_id`,`order_id`),
CONSTRAINT `z_many_ibfk_1` FOREIGN KEY (`customer_id`) REFERENCES `z_one` (`customer_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Или, если вы предпочитаете,

mysql> describe z_one;
+-------------+------------------+------+-----+---------+-------+
| Field       | Type             | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------+-------+
| customer_id | int(10) unsigned | NO   | PRI | 0       |       |
| name_last   | varchar(255)     | YES  |     | NULL    |       |
| name_first  | varchar(255)     | YES  |     | NULL    |       |
| dateadded   | datetime         | YES  |     | NULL    |       |
+-------------+------------------+------+-----+---------+-------+
4 rows in set (0.00 sec)mysql> describe z_many;
+-------------+------------------+------+-----+---------+-------+
| Field       | Type             | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------+-------+
| order_id    | varchar(15)      | NO   | PRI |         |       |
| customer_id | int(10) unsigned | YES  | MUL | NULL    |       |
| dateadded   | datetime         | YES  |     | NULL    |       |
+-------------+------------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

Далее вот запрос:

    $order_id = '22BD24';
$customer_id = 1;

try
{
$q = "INSERT INTO
z_many
(
order_id,
customer_id,
dateadded
)
VALUES
(
:order_id,
:customer_id,
NOW()
)
";
$stmt = $dbx_pdo->prepare($q);
$stmt->bindValue(':order_id', $order_id, PDO::PARAM_STR);
$stmt->bindValue(':customer_id', $customer_id, PDO::PARAM_INT);
$stmt->execute();

} catch(PDOException $err) {
// test case only.  do not echo sql errors to end users.
echo $err->getMessage();
}

Это приводит к следующей ошибке PDO:

SQLSTATE [23000]: нарушение ограничения целостности: 1062 Повторяющаяся запись
«22BD24» для ключа «ПЕРВИЧНЫЙ»

Тот же запрос работает нормально, когда обрабатывается mysqli, Почему PDO отклоняет INSERT с сообщением «дубликат записи», если дубликатов не найдено?

3

Решение

Поскольку не весь код доступен (со стороны php) на тот случай, если ваш запрос находится в каком-то цикле, самое быстрое (и, возможно, частично) решение этого заключается в следующем:

$order_id = '22BD24';
$customer_id = 1;

try {
$q = "INSERT INTO `z_many` (`order_id`,`customer_id`,`dateadded`)
VALUES (:order_id,:customer_id,NOW())
ON DUPLICATE KEY UPDATE `dateadded`=NOW()";

$stmt = $dbx_pdo->prepare($q);
$stmt->bindValue(':order_id', $order_id, PDO::PARAM_STR);
$stmt->bindValue(':customer_id', $customer_id, PDO::PARAM_INT);
$stmt->execute();

} catch(PDOException $err) {

// test case only.  do not echo sql errors to end users.
echo $err->getMessage();

}
2

Другие решения

Я скопировал схему SQL, которую вы предоставили в моей базе данных MySQL, и добавил код сценария, но с инициализацией PDO в начале:
$dbx_pdo = new PDO('mysql:host=127.0.0.1;dbname=test12;charset=utf8','root','');

.. и это работал нормально, но мои настройки php 5.5.9 и mysql 5.6.16

Поэтому я думаю, что ваш код выполняется дважды и, возможно, внутри транзакции, поэтому вы получаете откат. Нужно знать больше контекста

1

УДАЛИТЕ значение по умолчанию для столбца первичного ключа. Также используйте конструкцию

INSERT INTO (`field1`, `field2`, `...`) values (val1, val2, val3);

Если вы скажете, какое значение по умолчанию для вставок — некоторые версии mysql могут видеть ошибки при вставке. Вот почему вы должны использовать автоинкремент или вообще не использовать значение по умолчанию.

1

Просто выстрел в темноте. Я использую PDO с ORACLE PL / SQL только с bindParam (). И посмотрите на четвертый параметр ,15 если это PARAM_STR значение. Так что попробуйте, надеюсь, это поможет.

   $stmt->bindParam(':order_id', $order_id, PDO::PARAM_STR, 15);
$stmt->bindParam(':customer_id', $customer_id, PDO::PARAM_INT);

Это 15 описывает длину (bufffer-) из order_id в вашей таблице.

0
По вопросам рекламы [email protected]