(
tl;dr
:vá para a opção 3:INSERT com RETURNING ) Lembre-se que no postgresql não existe um conceito de "id" para tabelas, apenas sequências (que são normalmente, mas não necessariamente, usados como valores padrão para chaves primárias substitutas, com o pseudotipo SERIAL).
Se você estiver interessado em obter o id de uma linha recém-inserida, existem várias maneiras:
Opção 1:
CURRVAL(<sequence name>);
. Por exemplo:
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
SELECT currval('persons_id_seq');
O nome da sequência deve ser conhecido, é realmente arbitrário; neste exemplo, assumimos que a tabela
persons
tem um id
coluna criada com o SERIAL
pseudo-tipo. Para evitar depender disso e se sentir mais limpo, você pode usar pg_get_serial_sequence
: INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
SELECT currval(pg_get_serial_sequence('persons','id'));
Advertência:
currval()
só funciona após um INSERT
(que executou nextval()
), na mesma sessão . Opção 2:
LASTVAL();
Isso é semelhante ao anterior, só que você não precisa especificar o nome da sequência:ele procura a sequência modificada mais recente (sempre dentro de sua sessão, mesma ressalva acima).
Ambos
CURRVAL
e LASTVAL
são totalmente seguros simultâneos. O comportamento da sequência no PG é projetado para que sessões diferentes não interfiram, para que não haja risco de condições de corrida (se outra sessão inserir outra linha entre meu INSERT e meu SELECT, ainda recebo meu valor correto). No entanto eles têm um problema potencial sutil. Se o banco de dados possui algum TRIGGER (ou RULE) que, ao ser inserido em
persons
tabela, faz algumas inserções extras em outras tabelas... então LASTVAL
provavelmente nos dará o valor errado. O problema pode até acontecer com CURRVAL
, se as inserções extras forem feitas nas mesmas persons
tabela (isso é muito menos usual, mas o risco ainda existe). Opção 3:
INSERT
com RETURNING
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John') RETURNING id;
Esta é a maneira mais limpa, eficiente e segura de obter o id. Não tem nenhum dos riscos do anterior.
Desvantagens? Quase nenhum:você pode precisar modificar a maneira como chama sua instrução INSERT (na pior das hipóteses, talvez sua API ou camada de banco de dados não espere que um INSERT retorne um valor); não é SQL padrão (quem se importa); está disponível desde o Postgresql 8.2 (dezembro de 2006...)
Conclusão:Se puder, vá para a opção 3. Em outros lugares, prefira a 1.
Observação:todos esses métodos são inúteis se você pretende obter o último id inserido globalmente (não necessariamente pela sua sessão). Para isso, você deve recorrer a
SELECT max(id) FROM table
(claro, isso não lerá inserções não confirmadas de outras transações). Por outro lado, você nunca use
SELECT max(id) FROM table
em vez de uma das 3 opções acima, para obter o id gerado pelo seu INSERT
declaração, porque (além do desempenho) isso não é seguro concorrente:entre seu INSERT
e seu SELECT
outra sessão pode ter inserido outro registro.