es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Golang: ¿Cómo obtener el LastInsertId de una tabla con un disparador de creación?

Intentando obtener el id AUTO_INCREMENT de una tabla que tiene un disparador de INSERT/UPDATE en una tabla de “cambios”. Inicialmente, mi código seguía el patrón estándar:

stmt, err := db.Prepare("INSERT table SET name=?")
res, err := stmt.Exec(name)
lid, err := res.LastInsertId()

Pero el TRIGGER en la tabla estaba haciendo que LastInsertId devolviera el ID de la tabla de cambios, y no el nuevo registro en la tabla de inserción.

Ahora encontré que podía ajustar mi consulta para devolver SCOPE_IDENTITY en su lugar, y eso parecía devolver correctamente el ID que se estaba insertando, el problema aquí fue que si la inserción fallaba, SCOPE_IDENTITY devolvería NULL y Scan() intentaría insertar un valor NULL en una variable INT64. Lo cual en sí mismo es un manejo simple del valor… mi problema es cuál fue el error en la inserción. Parece que no puedo acceder al valor del error que causó que la inserción fallara, para poder registrar adecuadamente el problema y pasar el error de vuelta de manera elegante para corregirlo.

stmt, err := db.Prepare("INSERT table SET name=?; SELECT SCOPE_IDENTITY as last_insert_id")
res, err := stmt.QueryRow(name)

var lid int64
err := res.Scan(&lid)

He intentado usar una transacción, pero en el momento en que la inserción se completa, el SCOPE se cierra y la siguiente consulta en la transacción aún devuelve NULL.

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Solución para obtener el ID AUTO_INCREMENT con un disparador de INSERT/UPDATE

    Si te encuentras con un problema donde el disparador en la tabla causa que LastInsertId devuelva el ID de la tabla de cambios en lugar del registro recién insertado o actualizado, puedes usar la función SCOPE_IDENTITY para obtener el ID que se está insertando.

    stmt, err := db.Prepare("INSERT INTO tabla SET nombre=?; SELECT SCOPE_IDENTITY as last_insert_id")
    res, err := stmt.QueryRow(nombre)
    
    var lid int64
    err := res.Scan(&lid)
    

    Sin embargo, si la inserción falla y SCOPE_IDENTITY devuelve NULL, puede resultar difícil obtener el error que causó el fallo. Una solución sería usar una transacción para capturar el error y registrarlo de manera adecuada.

    tx, err := db.Begin()
    if err != nil {
        log.Fatal(err)
    }
    defer tx.Rollback()
    
    stmt, err := tx.Prepare("INSERT INTO tabla SET nombre=?; SELECT SCOPE_IDENTITY as last_insert_id")
    res, err := stmt.QueryRow(nombre)
    
    var lid int64
    err := res.Scan(&lid)
    if err != nil {
        // registrar el error y devolverlo de manera adecuada para su corrección
        log.Printf("La inserción falló con el error: %v", err)
        return err
    }
    
    err = tx.Commit()
    if err != nil {
        log.Fatal(err)
    }
    

    Ten en cuenta que incluso con una transacción, la función SCOPE_IDENTITY solo devolverá el último ID insertado dentro de la transacción. Por lo tanto, si necesitas insertar varios registros y obtener sus IDs, es posible que debas ejecutar las sentencias INSERT por separado y obtener los IDs individualmente.

Comments are closed.