59

Is there some way to get a value from the last inserted row?

I am inserting a row where the PK will automatically increase, and I would like to get this PK. Only the PK is guaranteed to be unique in the table.

I am using Java with a JDBC and PostgreSQL.

eflles
  • 6,606
  • 11
  • 41
  • 55
  • I am using JDBC 4, so the Statement.RETURN_GENERATED_KEYS did not work. I've got this error message: "org.postgresql.util.PSQLException: Returning autogenerated keys is not supported." But the PostgresSQL - RETURNING did work. – eflles Oct 28 '08 at 11:24
  • 1
    @Mark Rotteveel How did u add duplicate to this question? This was asked in 2008 the claimed duplicate question was asked on 2009. Its not appropriate no? – Arka Mallick Jul 06 '18 at 09:09
  • @Haramoz The one I closed to is the canonical duplicate for this question. Age is not an important factor in deciding what the duplicate target is, quality of the answers is. – Mark Rotteveel Jul 06 '18 at 09:27
  • @Mark Rotteveel ok, clear! – Arka Mallick Jul 06 '18 at 10:48

14 Answers14

68

With PostgreSQL you can do it via the RETURNING keyword:

PostgresSQL - RETURNING

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

It will return the value of "anyfield". "anyfield" may be a sequence or not.

To use it with JDBC, do:

ResultSet rs = statement.executeQuery("INSERT ... RETURNING ID");
rs.next();
rs.getInt(1);
Bastian Voigt
  • 5,311
  • 6
  • 47
  • 65
Luc M
  • 16,630
  • 26
  • 74
  • 89
  • 1
    Use RETURNING "ID" assuming the name of your PK is ID. – Jérôme Verstrynge Feb 06 '14 at 13:48
  • 6
    This is certainly the right SQL method, but the question asked how to do this with JDBC, and the other half of the problem is how to execute the statement. As mentioned in other answers, you either need to use `executeQuery()` (returns a ResultSet) instead of `executeUpdate()` (returns number of rows updated), OR use the `RETURN_GENERATED_KEYS` option to activate the ability to call `getGeneratedKeys()` method after calling `executeUpdate()`. – beldaz Aug 29 '14 at 07:26
  • This works - `ResultSet rs = preparedStatement.executeQuery(sqlQuery)`. – Shreyansh Jain Apr 08 '23 at 09:00
28

See the API docs for java.sql.Statement.

Basically, when you call executeUpdate() or executeQuery(), use the Statement.RETURN_GENERATED_KEYS constant. You can then call getGeneratedKeys to get the auto-generated keys of all rows created by that execution. (Assuming your JDBC driver provides it.)

It goes something along the lines of this:

Statement stmt = conn.createStatement();
stmt.execute(sql, Statement.RETURN_GENERATED_KEYS);
ResultSet keyset = stmt.getGeneratedKeys();
Andrew Watt
  • 2,757
  • 2
  • 20
  • 18
  • 7
    Oh if it were that easy. Unfortunately this doesn't work unless you have the correct Postgres driver version and even then the ResultSet has *all* of the fields and not just the generated id ones. – Gray May 20 '11 at 03:40
  • Aye, does not work for PostgreSQL – M.Stramm Jul 15 '12 at 18:26
  • 1
    As far as I know getGeneratedKeys() works only for the JDBC drivers that implement it. The correct thing would be IMHO to run `dmd = conn.getMetadata()` and then run `dmd.supportsGetGeneratedKeys()` to see whether this capability is supported or not. – Leonidas Tsampros May 15 '13 at 19:11
  • The only column returned in the `getGeneratedKeys()` is a `ROWID` - oracle 11. – AlikElzin-kilaka Apr 11 '16 at 08:33
17

If you're using JDBC 3.0, then you can get the value of the PK as soon as you inserted it.

Here's an article that talks about how : 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);
}
anjanb
  • 12,999
  • 18
  • 77
  • 106
13

Since PostgreSQL JDBC driver version 8.4-701 the PreparedStatement#getGeneratedKeys() is finally fully functional. We use it here almost one year in production to our full satisfaction.

In "plain JDBC" the PreparedStatement needs to be created as follows to make it to return the keys:

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

You can download the current JDBC driver version here (which is at the moment still 8.4-701).

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Does it matter if I use `PreparedStatement.RETURN_GENERATED_KEYS` vs `Statement.RETURN_GENERATED_KEYS`? – csharpfolk Jan 01 '17 at 13:58
  • 1
    @csharpfolk: Nope. It's defined in `Statement` and `PreparedStatement extends Statement`. See also its source code and javadoc. – BalusC Jan 01 '17 at 14:51
8

The sequences in postgresql are transaction safe. So you can use the

currval(sequence)

Quote:

currval

Return the value most recently obtained by nextval for this sequence in the current session. (An error is reported if nextval has never been called for this sequence in this session.) Notice that because this is returning a session-local value, it gives a predictable answer even if other sessions are executing nextval meanwhile.

svrist
  • 7,042
  • 7
  • 44
  • 67
  • Isn't it possible that another transaction could change the value of the sequence between his INSERT and his SELECT currval() ? I'm assuming that each of those operations would take place in separate transactions. – matt b Oct 27 '08 at 19:10
  • 3
    No. that exactly what the currval function is for. – svrist Dec 10 '09 at 08:27
7

Here is how I solved it, based on the answers here:

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));
        }
eflles
  • 6,606
  • 11
  • 41
  • 55
4

If you are using Statement, go for the following

//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);

If you are using PreparedStatement, go for the following

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);
nhahtdh
  • 55,989
  • 15
  • 126
  • 162
1

Use sequences in postgres for id columns:

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

SELECT currval('MySequence');

currval will return the current value of the sequence in the same session.

(In MS SQL, you would use @@identity or SCOPE_IDENTITY())

BradC
  • 39,306
  • 13
  • 73
  • 89
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();
Gray
  • 115,027
  • 24
  • 293
  • 354
0

Use that simple code:

// 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)
danigonlinea
  • 1,113
  • 1
  • 14
  • 20
0

If you are in a transaction you can use SELECT lastval() after an insert to get the last generated id.

mihu86
  • 969
  • 8
  • 9
0

Don't use SELECT currval('MySequence') - the value gets incremented on inserts that fail.

smilek
  • 19
  • 1
  • So what? He just asked for unique values, not contiguous values (which is an impossible goal in a system with parallel abortable transactions). – bortzmeyer May 26 '10 at 06:54
  • 3
    The original question: "Is there some way to get a value from the last inserted row?" Code that uses currval(seq) to form a SELECT statement for obtaining the last inserted row may fail to produce expected results. – smilek Jun 01 '10 at 18:08
0

For MyBatis 3.0.4 with Annotations and Postgresql driver 9.0-801.jdbc4 you define an interface method in your Mapper like

public interface ObjectiveMapper {

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

Note that @Select is used instead of @Insert.

emicklei
  • 1,321
  • 11
  • 10
0

for example:

 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);
                }
            } 

with ,Statement.RETURN_GENERATED_KEYS);" no found.

fernando
  • 51
  • 2