PHP MYSQL PDO -> Error fatal 23000 aunque existe un procedimiento especial

Tengo una tabla en mi db. Mi tabla tiene varios campos, incluido un campo de identificación de incremento automático establecido como clave principal y otro campo llamado "referencia" que configuré como único. Para completar esa tabla, tengo un script php que inserta registros en esa tabla usando pdo. Cada vez que una inserción se ha realizado con éxito (lo que significa que la 'referencia' no existía en la tabla), incremento una variable llamada $newOnes. Si el valor 'referencia' ya está en la tabla, se activa una excepción con el código 23000. En ese caso, incremento otra variable llamada $doublons. Desafortunadamente, mi script está provocando un error fatal con la excepción 23000 cuando el ciclo while está "manejando" el último registro de la tabla. Y no lo entiendo. Gracias de antemano por su ayuda. Salud. Bagazo.

Mi código php:

try {
  $connexion = connexion('localhost', 'user', 'user', 'mydb');
  $connexion->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  $qry_bat = $connexion->query('SELECT...');
  $ins_db = $connexion->prepare('INSERT...');
}
catch (PDOException $e) {
  echo $e->getMessage();
}

while($row = $qry_bat->fetch(PDO::FETCH_ASSOC)) {
  try {
    $ins_db->execute(array(...));
    $newOnes++;
  }
  catch (PDOException $e) {
    if ($e->getCode() != 23000) {
      echo '<span class="msg-alert">'.$e->getMessage().'</span>';
    } else {
      $doublons++;
    }
  }
}

El error fatal que recibo (tenga en cuenta que la línea 22 se refiere a la línea while (...)):

Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[23000]:  
Integrity constraint violation: 1062 Duplicate entry 'theFieldContentOfTheLastRecordOfTheTable' for key 'theFieldNameReference' in  
/myFilePath/file.php:22 Stack trace: #0 /myFilePath/file.php(22): PDOStatement->fetch(2)  
#1 {main} thrown in /myFilePath/file.php on line 22

EDITAR //////////

tabla original (cosas para mencionar):
identificación incrementada automáticamente

tabla para insertar en (cosas para mencionar):
incrementado automáticamente en el campo de identificación
ÍNDICE ÚNICO sobre referencia

preguntado el 03 de mayo de 12 a las 11:05

No ayuda a explicar por qué no detecta la excepción, pero podría INSERT todos sus valores de una sola vez, usando INSERT IGNORE ... VALUES (...), (...), ..., luego llame $ins_db->rowCount() para descubrir el valor de $newOnes (a partir del cual $doublons se puede calcular como $qry_bat->rowCount() - $newOnes). De hecho, probablemente puedas ahorrarte la ejecución $qry_bat en conjunto usando INSERT IGNORE INTO ... SELECT .... -

¿La solución anterior no sirve? ¿O desea una respuesta muy específica sobre por qué no se detecta la excepción? -

Hola eggyval. Me gustaría entender por qué se activa esa excepción... Gracias -

pregunta similar aquí, en el que el OP dice "Actualizar la versión de PHP a 5.3.10 parece solucionar este problema". ¿Podría ser un error de PHP? -

3 Respuestas

(Actualizando a una respuesta)

Parece este error, que sigue abierta después de casi cinco años; prueba en su lugar:

while (true) {
  try {
    $row = $qry_bat->fetch(PDO::FETCH_ASSOC);
    if (!$row) break;
    $ins_db->execute(array(...));
    $newOnes++;
  }
  catch (PDOException $e) {
    if ($e->getCode() != 23000) {
      echo '<span class="msg-alert">'.$e->getMessage().'</span>';
    } else {
      $doublons++;
    }
  }
}

contestado el 26 de mayo de 12 a las 11:05

Ya encontré una solución al poner una prueba antes de mi ciclo while y una captura al final. Eso está funcionando. Sin embargo, me gustaría entender por qué el código original no funciona, ya que no hay ninguna razón por la que no debería... - Marc

Error muy dudoso, y aún más dudoso es el hecho de que en este caso hay 2 objetos PDOStatement separados. - Mihai Stancu

@Marc: sospecho que la conexión PDO no está restableciendo su estado de error después de la INSERT falla, por lo que la siguiente llamada a fetch() lanza esa misma excepción (fuera de su original try cuadra). Si eso es lo que está sucediendo, definitivamente es un error/comportamiento no documentado (y no hay forma de restablecer el estado de error del objeto PDO); una solución alternativa sería utilizar dos objetos PDO: uno para la obtención y otro para la inserción. - huevo

La cuestión es que la inserción falla muchas veces durante el bucle porque tengo varios doblones y todo funciona bien. Excepto cuando el ciclo while está ejecutando el último ciclo. Entonces, de acuerdo con el hecho de que el "procedimiento de falla de inserción" funciona bien para todos los bucles (excepto el último), asumo que la conexión PDO logra restablecer su estado de error correctamente después de que falla una inserción ... - Marc

@Marc: es completamente posible que un error de "lanzamiento de una excepción pasada" ocurra solo cuando fetch() falla debido a que no hay más registros en el conjunto de registros. Sea lo que sea, esto parece un error. - huevo

El seguimiento de la pila muestra la excepción que tiene lugar en la recuperación que está fuera de los bloques try/catch.

La declaración SELECT está desencadenando:

Integrity constraint violation: 1062 Duplicate entry 'theFieldContentOfTheLastRecordOfTheTable'

Hay una clave única llamada el contenido del campo del último registro de la tabla con el que está en conflicto.

¿Puede publicar el esquema para que veamos cómo esto podría afectar la integridad?

contestado el 26 de mayo de 12 a las 11:05

Hola Mihai. Entiendo la excepción. Lo que no entiendo es por qué se dispara... - Marc

El seguimiento de la pila muestra la excepción que tiene lugar en el ha podido recuperar que está fuera de la trata de atraparlo bloques. - Mihai Stancu

Absolutamente... Y no entiendo por qué se dispara ese error. - Marc

Tampoco entiendo, todavía, por qué una selección presumiblemente simple desencadenaría una violación de integridad. - Mihai Stancu

Busque datos sucios/duplicados YA en esa columna. Algunas aplicaciones permiten que se aplique una restricción "suelta" DESPUÉS de que ya se hayan capturado los datos. Esto puede haber sucedido en su caso.

respondido 03 nov., 14:12

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.