3

Im wondering if the way i use to retrieve the id of the last row inserted in a postgresql table is efficent..

It works, obviously, but referencing on the serial sequence currval value could be problematic when i have many users adding rows in the same table at the same time.

My actual way is:

$pgConnection = pg_connect('host=127.0.0.1 dbname=test user=myuser password=xxxxx')or die('cant connect');

$insert = pg_query("INSERT INTO customer (name) VALUES ('blabla')");
$last_id_query = pg_query("SELECT currval('customer_id_seq')");
$last_id_results = pg_fetch_assoc($last_id_query);
print_r($last_id_results);
pg_close($pgConnection);

Well, its just a test atm. But anyway, i can see 3 issues with this way:

  1. Referencing on the customer_id_seq, if two user do the same thing in the same time, could happen that them both get the same id from that way... or not?
  2. I have to know the table's sequence name. Becose pg_get_serial_sequence dont works for me (im newbie on postgresql, probably is a configuration issue)

Any suggestion/better ways?

p.s: i can't use the PDO, becose seem lack a bit with the transaction savepoint; I wont use zend and, in the end, i'll prefer to use the php pg_* functions (maybe i'll build up my classes in the end)

EDIT:

@SpliFF(thet deleted his answer): this would works better?

$pgConnection = pg_connect('host=127.0.0.1 dbname=test user=myuser password=xxxxx')or die('cant connect');

pg_query("BEGIN");

$insert = pg_query("INSERT INTO customer (name) VALUES ('blabla')");

$last_id_query = pg_query("SELECT currval('customer_id_seq')");

$last_id_results = pg_fetch_assoc($last_id_query);

print_r($last_id_results);

//do somethings with the new customer id

pg_query("COMMIT");

pg_close($pgConnection);
Strae
  • 18,807
  • 29
  • 92
  • 131

3 Answers3

7

If you use a newer version of PostgreSQL (> 8.1) you should use the RETURNING clause of INSERT (and UPDATE) command.

OTOH if you insist on using one of the sequence manipulation functions, please read the fine manual. A pointer: "Notice that because this is returning a session-local value, it gives a predictable answer whether or not other sessions have executed nextval since the current session did."

Milen A. Radev
  • 60,241
  • 22
  • 105
  • 110
  • I dont want to use the sequence manipulation functions - but actually - they seem to be the only way to retrieve the last id without using PDO! – Strae May 21 '09 at 10:22
  • ..and what about if i am using postgresql-7.4 and i cant upgrade? – Strae May 21 '09 at 10:24
  • 1
    7.4 is *ancient*. Almost no one will support it anymore; post a bug in 7.4 to the dev lists and they'll just laugh at you. – kquinn May 21 '09 at 10:37
  • Oh, i understand.. i'll try to upgrate to 8.3 then. But why the hell debian apt-get still install only the 7.4, and no way to upgrate it by apt-get? – Strae May 21 '09 at 10:41
  • Because you're using an old version of Debian (4.0 shipped with pgsql 7.4). You either have to use backports.org or upgrade to Debian 5.0 which ships with pgsql 8.3. – Milen A. Radev May 21 '09 at 10:51
  • I suppose i have to shoot the server admin, then ;) – Strae May 21 '09 at 10:56
  • DaNieL - please check the "OTOH" part of Milen answer. Basically - currval() is safe on every PostgreSQL. –  May 21 '09 at 14:01
  • Yes, i just made some try and in the end i'll go for the 'returning query' inside the transaction... should be even faster and easier then the currval... i switched to 8.3.7 :) – Strae May 22 '09 at 06:26
1

Insert and check curval(seq) inside one transaction. Before commiting transaction you'll see curval(seq) for your query and no matter who else inserted at the same time.

Don't remember the syntax exactly - read in manual (last used pgsql about 3 years ago), but in common it looks like this:

BEGIN TRANSACTION;
INSERT ...;
SELECT curval(seq);
COMMIT;
Jet
  • 1,171
  • 6
  • 8
  • Mmmh.. but if 2 transaction happen on the same time, wont the currval value be the same? – Strae May 21 '09 at 12:03
  • No. Every thansaction safely operates wit it's own state and then pgsql flushes all transactions results into tables on hard disk. That is why transactions were invented ;). – Jet May 21 '09 at 12:32
  • transactions are not relevant to currval. –  May 21 '09 at 13:59
  • OK, use "SELECT MAX(id)" or "SELECT id ORDER BY id DESC LIMIT 1" instead... Actually, not sure about currval() - don't remember exactly. But the values in table during transaction sure have to be actual for exact state, but not for all the server. So inside transaction you may get real insert_id for your last query. – Jet May 21 '09 at 14:24
-1

ex. minsert into log (desc,user_id) values ('drop her mind',6) returning id