2008-10-27 25 views
49

¿Hay alguna manera de obtener un valor de la última fila insertada?¿Cómo obtener un valor de la última fila insertada?

Estoy insertando una fila donde la PK aumentará automáticamente, y me gustaría obtener esta PK. Solo se garantiza que el PK será único en la tabla.

Estoy usando Java con un JDBC y PostgreSQL.

+0

Estoy usando JDBC 4, por lo que el Statement.RETURN_GENERATED_KEYS no funcionó. Recibo este mensaje de error: "org.postgresql.util.PSQLException: No se admite el retorno de claves autogeneradas". Pero el PostgresSQL - RETORNO funcionó. – eflles

Respuesta

49

Con PostgreSQL puede hacerlo a través de la palabra clave de Regreso:

PostgresSQL - RETURNING

INSERT INTO mytable(field_1, field_2,...) 
VALUES (value_1, value_2) RETURNING anyfield 

Volverá el valor de "anyfield". "anyfield" puede ser una secuencia o no.

Para utilizarlo con JDBC, hacer:

ResultSet rs = statement.executeQuery("INSERT ... RETURNING ID"); 
rs.next(); 
rs.getInt(1); 
+0

Use el "ID" DEVUELTO suponiendo que el nombre de su PK es ID. – JVerstry

+5

Este es sin duda el método SQL correcto, pero la pregunta que se le preguntó cómo hacer esto con JDBC, y la otra mitad del problema es cómo ejecutar la instrucción. Como se menciona en otras respuestas, debe usar 'executeQuery()' (devuelve un ResultSet) en lugar de 'executeUpdate()' (devuelve el número de filas actualizadas), O use la opción 'RETURN_GENERATED_KEYS' para activar la habilidad de llamar' Método getGeneratedKeys() 'después de llamar a' executeUpdate() '. – beldaz

8

Las secuencias en postgresql son transaccionales. Por lo tanto se puede utilizar el

currval(sequence) 

Quote:

currval

retorno del último valor obtenido por nextval para esta secuencia en la sesión actual. (Un error se informó si nextval nunca ha sido llamada para esta secuencia en esta sesión .) Tenga en cuenta que debido a esto es devolver un valor de sesión local, que da una respuesta predecible otros incluso si sesiones están ejecutando nextval mientras tanto.

+0

¿No es posible que otra transacción pueda cambiar el valor de la secuencia entre su INSERT y su currval SELECT()? Estoy asumiendo que cada una de esas operaciones se llevaría a cabo en transacciones separadas. –

+3

No, eso es exactamente para lo que es la función de currval. – svrist

1

utilizar secuencias en Postgres para las columnas id:

INSERT mytable(myid) VALUES (nextval('MySequence')); 

SELECT currval('MySequence'); 

currval devolverá el valor actual de la secuencia en la misma sesión.

(En MS SQL, se utiliza @@ identidad o SCOPE_IDENTITY())

28

Consulte los documentos de la API de java.sql.Statement.

Básicamente, cuando llame a executeUpdate() o executeQuery(), use la constante Statement.RETURN_GENERATED_KEYS. A continuación, puede llamar al getGeneratedKeys para obtener las claves generadas automáticamente de todas las filas creadas por esa ejecución. (Asumiendo que su controlador JDBC proporciona.)

Es algo a lo largo de las líneas de este:

Statement stmt = conn.createStatement(); 
stmt.execute(sql, Statement.RETURN_GENERATED_KEYS); 
ResultSet keyset = stmt.getGeneratedKeys(); 
+0

Muy bien agnóstico de base de datos. –

+7

Oh, si fuera tan fácil.Lamentablemente, esto no funciona a menos que tenga la versión correcta del controlador Postgres e incluso entonces el ResultSet tiene * todos * los campos y no solo los ID generados. – Gray

+0

Sí, no funciona para PostgreSQL –

16

Si está utilizando JDBC 3.0, entonces se puede obtener el valor de la PK tan pronto como se lo insertó.

He aquí un artículo que habla sobre cómo: https://www.ibm.com/developerworks/java/library/j-jdbcnew/

Statement stmt = conn.createStatement(); 
// Obtain the generated key that results from the query. 
stmt.executeUpdate("INSERT INTO authors " + 
        "(first_name, last_name) " + 
        "VALUES ('George', 'Orwell')", 
        Statement.RETURN_GENERATED_KEYS); 
ResultSet rs = stmt.getGeneratedKeys(); 
if (rs.next()) { 
    // Retrieve the auto generated key(s). 
    int key = rs.getInt(1); 
} 
+4

Tenga en cuenta que esto no funcionará para Oracle (estoy usando 10g) http://stackoverflow.com/questions/1976625/value-from-last-inserted-row-in-db –

+1

funciona bien con postgresql-9.2-1002.jdbc4.jar –

+0

Gracias por el enlace – gmustudent

7

Aquí es cómo lo resolví, basado en las respuestas aquí:

Connection conn = ConnectToDB(); //ConnectToDB establishes a connection to the database. 
String sql = "INSERT INTO \"TableName\"" + 
     "(\"Column1\", \"Column2\",\"Column3\",\"Column4\")" + 
     "VALUES ('value1',value2, 'value3', 'value4') RETURNING 
     \"TableName\".\"TableId\""; 
PreparedStatement prpState = conn.prepareStatement(sql); 
ResultSet rs = prpState.executeQuery(); 
if(rs.next()){ 
     System.out.println(rs.getInt(1)); 
     } 
0

No utilice currval SELECT ('MySequence'): el valor se incrementa en las inserciones que fallan.

+0

¿Y qué? Solo pidió valores únicos, no valores contiguos (que es un objetivo imposible en un sistema con transacciones abortables paralelas). – bortzmeyer

+2

La pregunta original: "¿Hay alguna forma de obtener un valor de la última fila insertada?" El código que usa currval (seq) para formar una instrucción SELECT para obtener la última fila insertada puede no producir los resultados esperados. – smilek

10

Desde el controlador PostgreSQL JDBC versión 8.4-701, el PreparedStatement#getGeneratedKeys() finalmente es completamente funcional. Lo usamos aquí casi un año en producción para nuestra plena satisfacción.

En "JDBC normal" los PreparedStatement tiene que ser creado de la siguiente manera para hacer que vuelva las teclas:

statement = connection.prepareStatement(SQL, Statement.RETURN_GENERATED_KEYS); 

Puede descargar la versión actual del controlador JDBC here (que es en este momento todavía 8.4- 701).

+0

¿Importa si uso 'PreparedStatement.RETURN_GENERATED_KEYS' contra' Statement.RETURN_GENERATED_KEYS'? – csharpfolk

+0

@csharpfolk: No. Se define en 'Statement' y' PreparedStatement extends Statement'. Ver también su código fuente y javadoc. – BalusC

1
PreparedStatement stmt = getConnection(PROJECTDB + 2) 
    .prepareStatement("INSERT INTO fonts (font_size) VALUES(?) RETURNING fonts.*"); 
stmt.setString(1, "986"); 
ResultSet res = stmt.executeQuery(); 
while (res.next()) { 
    System.out.println("Generated key: " + res.getLong(1)); 
    System.out.println("Generated key: " + res.getInt(2)); 
    System.out.println("Generated key: " + res.getInt(3)); 
} 
stmt.close(); 
0

Para MyBatis 3.0.4 con anotaciones y controlador PostgreSQL 9.0-801.jdbc4 se define un método de interfaz en su Mapper como

public interface ObjectiveMapper { 

@Select("insert into objectives" + 
     " (code,title,description) values" + 
     " (#{code}, #{title}, #{description}) returning id") 
int insert(Objective anObjective); 

Tenga en cuenta que @Seleccione se utiliza en lugar de @Insert.

0

por ejemplo:

 
Connection conn = null; 
      PreparedStatement sth = null; 
      ResultSet rs =null; 
      try { 
       conn = delegate.getConnection(); 
       sth = conn.prepareStatement(INSERT_SQL); 
       sth.setString(1, pais.getNombre()); 
       sth.executeUpdate(); 
       rs=sth.getGeneratedKeys(); 
       if(rs.next()){ 
        Integer id = (Integer) rs.getInt(1); 
        pais.setId(id); 
       } 
      } 

con ,Statement.RETURN_GENERATED_KEYS);" No se han encontrado.

0

Uso ese código simple:

// Do your insert code 

myDataBase.execSQL("INSERT INTO TABLE_NAME (FIELD_NAME1,FIELD_NAME2,...)VALUES (VALUE1,VALUE2,...)"); 

// Use the sqlite function "last_insert_rowid" 

Cursor last_id_inserted = yourBD.rawQuery("SELECT last_insert_rowid()", null); 

// Retrieve data from cursor. 

last_id_inserted.moveToFirst(); // Don't forget that! 

ultimo_id = last_id_inserted.getLong(0); // For Java, the result is returned on Long type (64) 
3

Si está utilizando Statement, ir a la siguiente

//MY_NUMBER is the column name in the database 
String generatedColumns[] = {"MY_NUMBER"}; 
Statement stmt = conn.createStatement(); 

//String sql holds the insert query 
stmt.executeUpdate(sql, generatedColumns); 

ResultSet rs = stmt.getGeneratedKeys(); 

// The generated id 

if(rs.next()) 
long key = rs.getLong(1); 

Si está utilizando PreparedStatement, ir a la siguiente

String generatedColumns[] = {"MY_NUMBER"}; 
PreparedStatement pstmt = conn.prepareStatement(sql,generatedColumns); 
pstmt.setString(1, "qwerty"); 

pstmt.execute(); 
ResultSet rs = pstmt.getGeneratedKeys(); 
if(rs.next()) 
long key = rs.getLong(1); 
0

Si está en una transacción puede usar SELECT lastval() después de un i nsert para obtener la última identificación generada.

Cuestiones relacionadas