In PostgreSQL, how do I get the last id inserted into a table?
In MS SQL there is SCOPE_IDENTITY().
Please do not advise me to use something like this:
select max(id) from table
If you are AUTO_INCREMENT with column, then you can use last_insert_id() method. This method gets the ID of the last inserted record in MySQL. Insert some records in the table using insert command.
SELECT @@IDENTITY @@IDENTITY will return the last identity value entered into a table in your current session. While @@IDENTITY is limited to the current session, it is not limited to the current scope.
The LAST_INSERT_ID() function returns the AUTO_INCREMENT id of the last row that has been inserted or updated in a table.
To get a table OID, cast to the object identifier type regclass (while connected to the same DB): SELECT 'mytbl'::regclass::oid; This finds the first table (or view, etc.) with the given name along the search_path or raises an exception if not found.
( tl;dr
: goto option 3: INSERT with RETURNING )
Recall that in postgresql there is no "id" concept for tables, just sequences (which are typically but not necessarily used as default values for surrogate primary keys, with the SERIAL pseudo-type).
If you are interested in getting the id of a newly inserted row, there are several ways:
Option 1: CURRVAL(<sequence name>);
.
For example:
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John'); SELECT currval('persons_id_seq');
The name of the sequence must be known, it's really arbitrary; in this example we assume that the table persons
has an id
column created with the SERIAL
pseudo-type. To avoid relying on this and to feel more clean, you can use instead pg_get_serial_sequence
:
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John'); SELECT currval(pg_get_serial_sequence('persons','id'));
Caveat: currval()
only works after an INSERT
(which has executed nextval()
), in the same session.
Option 2: LASTVAL();
This is similar to the previous, only that you don't need to specify the sequence name: it looks for the most recent modified sequence (always inside your session, same caveat as above).
Both CURRVAL
and LASTVAL
are totally concurrent safe. The behaviour of sequence in PG is designed so that different session will not interfere, so there is no risk of race conditions (if another session inserts another row between my INSERT and my SELECT, I still get my correct value).
However they do have a subtle potential problem. If the database has some TRIGGER (or RULE) that, on insertion into persons
table, makes some extra insertions in other tables... then LASTVAL
will probably give us the wrong value. The problem can even happen with CURRVAL
, if the extra insertions are done intto the same persons
table (this is much less usual, but the risk still exists).
Option 3: INSERT
with RETURNING
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John') RETURNING id;
This is the most clean, efficient and safe way to get the id. It doesn't have any of the risks of the previous.
Drawbacks? Almost none: you might need to modify the way you call your INSERT statement (in the worst case, perhaps your API or DB layer does not expect an INSERT to return a value); it's not standard SQL (who cares); it's available since Postgresql 8.2 (Dec 2006...)
Conclusion: If you can, go for option 3. Elsewhere, prefer 1.
Note: all these methods are useless if you intend to get the last inserted id globally (not necessarily by your session). For this, you must resort to SELECT max(id) FROM table
(of course, this will not read uncommitted inserts from other transactions).
Conversely, you should never use SELECT max(id) FROM table
instead one of the 3 options above, to get the id just generated by your INSERT
statement, because (apart from performance) this is not concurrent safe: between your INSERT
and your SELECT
another session might have inserted another record.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With