Est-il possible d'obtenir une valeur à partir de la dernière ligne insérée?
J'insère une ligne où la PK augmentera automatiquement et j'aimerais obtenir cette PK. Seul le PK est garanti d'être unique dans la table.
J'utilise Java avec JDBC et PostgreSQL.
Avec PostgreSQL, vous pouvez le faire via le mot-clé RETURNING:
INSERT INTO mytable( field_1, field_2,... )
VALUES ( value_1, value_2 ) RETURNING anyfield
Il retournera la valeur de "anyfield". "anyfield" peut être une séquence ou non.
Pour l'utiliser avec JDBC, faites:
ResultSet rs = statement.executeQuery("INSERT ... RETURNING ID");
rs.next();
rs.getInt(1);
Voir la documentation de l'API pour Java.sql.Statement .
En gros, lorsque vous appelez executeUpdate()
ou executeQuery()
, utilisez la constante Statement.RETURN_GENERATED_KEYS
. Vous pouvez ensuite appeler getGeneratedKeys
pour obtenir les clés générées automatiquement de toutes les lignes créées par cette exécution. (En supposant que votre pilote JDBC le fournisse.)
Cela va dans le sens de ceci:
Statement stmt = conn.createStatement();
stmt.execute(sql, Statement.RETURN_GENERATED_KEYS);
ResultSet keyset = stmt.getGeneratedKeys();
Si vous utilisez JDBC 3.0, vous pouvez obtenir la valeur du PK dès que vous l’avez insérée.
Voici un article qui explique comment: 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);
}
Depuis la version du pilote PostgreSQL JDBC 8.4-701 la PreparedStatement#getGeneratedKeys()
est enfin pleinement fonctionnelle. Nous l'utilisons ici depuis presque un an en production à notre entière satisfaction.
Dans "JDBC simple", la PreparedStatement
doit être créée comme suit pour pouvoir renvoyer les clés:
statement = connection.prepareStatement(SQL, Statement.RETURN_GENERATED_KEYS);
Vous pouvez télécharger la version actuelle du pilote JDBC ici (qui est encore à l’heure actuelle 8.4-701).
Les séquences dans postgresql sont sécurisées pour les transactions. Afin que vous puissiez utiliser le
currval(sequence)
currval
Renvoie la valeur la plus récente obtenue par nextval pour cette séquence dans la session en cours. (Une erreur est signalée. Si. Nextval n'a jamais été appelé Appelé pour cette séquence dans cette session ) Notez que, car il s'agit de. renvoyer une valeur de session-local, it donne une réponse prévisible même si d'autres sessions sont en cours d'exécution nextval pendant ce temps.
Voici comment je l'ai résolu, basé sur les réponses ici:
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));
}
Si vous utilisez Statement
, optez pour ce qui suit
//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 vous utilisez PreparedStatement
, optez pour ce qui suit
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);
Utilisez les séquences dans postgres pour les colonnes id:
INSERT mytable(myid) VALUES (nextval('MySequence'));
SELECT currval('MySequence');
currval renverra la valeur actuelle de la séquence dans la même session.
(Dans MS SQL, vous utiliseriez @@ identity ou SCOPE_IDENTITY ())
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();
Pour MyBatis 3.0.4 avec Annotations et le pilote Postgresql 9.0-801.jdbc4, vous définissez une méthode d’interface dans votre mappeur, telle que
public interface ObjectiveMapper {
@Select("insert into objectives" +
" (code,title,description) values" +
" (#{code}, #{title}, #{description}) returning id")
int insert(Objective anObjective);
Notez que @Select est utilisé à la place de @Insert.
N'utilisez pas SELECT currval ('MySequence') - la valeur est incrémentée lorsque les insertions échouent.
Si vous êtes dans une transaction, vous pouvez utiliser SELECT lastval()
après une insertion pour obtenir le dernier identifiant généré.
par exemple:
Connexion conn = null; PreparedStatement sth = null; ResultSet rs = null; essayez { 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); } }
avec ,Statement.RETURN_GENERATED_KEYS);"
non trouvé.
Utilisez ce code 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)