views:

1318

answers:

4

Hi guys!

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);
+7  A: 

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
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!
DaNieL
..and what about if i am using postgresql-7.4 and i cant upgrade?
DaNieL
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
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?
DaNieL
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
I suppose i have to shoot the server admin, then ;)
DaNieL
DaNieL - please check the "OTOH" part of Milen answer. Basically - currval() is safe on every PostgreSQL.
depesz
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 :)
DaNieL
A: 

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
Mmmh.. but if 2 transaction happen on the same time, wont the currval value be the same?
DaNieL
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
transactions are not relevant to currval.
depesz
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
A: 

The edited answer is realiable.

Csaba Kétszeri
A: 

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

ToCaDo157