2012-02-01 16 views
6

¿Hay alguna forma de recuperar el ID de un registro (clave principal) después de una inserción cuando el error mysql devuelve una clave duplicada?Obtener ID de registro cuando mysql devuelve un error duplicado

E.G. Cómo iba a ir sobre ella:

$sql = "INSERT INTO table (`col1`, `col2`) VALUES ('$val1', '$val2')"; 
$result = mysql_query($sql); 
if($result){ 
    $id = mysql_insert_id(); 
} 
else { 
    if(stristr(mysql_error(), "duplicate"){ 
    $sql = "SELECT `id` FROM `table` WHERE `col1`='$val1' AND `col2`='$val2'"; 
    $result = mysql_query($sql); 
    $row = mysql_fetch_array($result); 
    $id = $row['id']; 
    } 
    else { 
    die(mysql_error()); 
    } 
} 

Aquí he tenido que hacer dos sentencias SQL que no sólo toman tiempo y esfuerzo, pero duplican código.

No puedo usar ON DUPLICATE KEY UPDATE porque deseo actualizar una tabla diferente usando la última identificación insertada o la identificación del registro que no se puede duplicar.

Entonces, ¿tengo razón en lo que estoy haciendo? ¿O hay una forma de obtener la identificación de la fila?

Gracias

Respuesta

6

MySQL no le dirá qué registro tiene el valor original, tendrá que encontrar tú mismo. Aquí tiene algunos consejos:

  • Buscando el duplicate subcadena en el texto del mensaje de error no se ve muy robusto. Puede probar el valor de mysql_errno() contra el código de entrada duplicada, que es 1062 (you can find all codes in the manual).
  • La extensión de MySQL no proporciona un mecanismo para averiguar el nombre de la clave violado, por lo que tendrá que utilizar el enfoque no robusta de analizar el texto del mensaje de error:

    if(preg_match("/Duplicate entry '.*' for key '(.*)'/Ui", mysql_error(), $matches)){ 
        $violated_key = $matches[1]; 
    }else{ 
        throw new Exception('Could not find violated key name'); 
    } 
    
  • Alternativamente, basta con ejecutar una consulta anterior (no hay razón para evitarlo):

    SELECT id 
    FROM table 
    WHERE col1=... AND col2=... 
    FOR UPDATE 
    

    La cláusula FOR UPDATE se bloqueará filas coincidentes para evitar (suponiendo InnoDB) las condiciones de carrera.

+0

Genial, gracias por la información y los consejos. –

+0

Me alegro de que haya ayudado. Permítanme agregar una nota: obviamente, 'FOR UPDATE' no bloqueará nada si no hay coincidencias. Todavía puede obtener el registro creado por otro proceso simultáneo justo después del control. Solo tenlo en cuenta. –

+0

Ok, gracias. No estoy usando InnoDB, y nunca lo hice, ¡así que no estoy seguro de lo que estás hablando! : p Pero lo investigaré. :) –

Cuestiones relacionadas