PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Função PostgreSQL para o último ID inserido


( 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.