No PostgreSQL, como obtenho o último ID inserido em uma tabela?
No MS SQL, há SCOPE_IDENTITY ().
Por favor, não me aconselhe a usar algo como isto:
select max(id) from table
No PostgreSQL, como obtenho o último ID inserido em uma tabela?
No MS SQL, há SCOPE_IDENTITY ().
Por favor, não me aconselhe a usar algo como isto:
select max(id) from table
Respostas:
( tl;dr
: goto opção 3: INSERT com RETURNING)
Lembre-se de que no postgresql não existe um conceito de "id" para tabelas, apenas seqüências (que geralmente são usadas, mas não necessariamente, como valores padrão para chaves primárias substitutas, com o pseudo-tipo SERIAL ).
Se você estiver interessado em obter o ID de uma linha recém-inserida, há 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
tenha uma id
coluna criada com o SERIAL
pseudo-tipo. Para evitar confiar nisso 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 foi executado nextval()
), na mesma sessão .
Opção 2: LASTVAL();
Isso é semelhante ao anterior, mas você não precisa especificar o nome da sequência: ele procura a sequência modificada mais recente (sempre dentro da sua sessão, a mesma ressalva acima).
Ambos CURRVAL
e LASTVAL
são totalmente simultâneos seguros. O comportamento da sequência no PG é projetado para que uma sessão diferente não interfira, portanto não há risco de condições de corrida (se outra sessão inserir outra linha entre o meu INSERT e meu SELECT, ainda assim recebo meu valor correto).
No entanto, eles têm um problema potencial sutil. Se o banco de dados tiver algum TRIGGER (ou RULE) que, ao ser inserido na persons
tabela, faça algumas inserções extras em outras tabelas ... LASTVAL
provavelmente nos fornecerá o valor errado. O problema pode até acontecer CURRVAL
se as inserções extras forem feitas na mesma persons
tabela (isso é muito menos usual, mas o risco ainda existe).
Opção 3: INSERT
comRETURNING
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John') RETURNING id;
Essa é 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 camada API ou DB não espere que uma INSERT retorne um valor); não é SQL padrão (quem se importa); está disponível desde o Postgresql 8.2 (dez 2006 ...)
Conclusão: Se puder, vá para a opção 3. Em outros lugares, prefira 1.
Nota: 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 deve usar SELECT max(id) FROM table
uma das três opções acima para obter o ID gerado apenas por sua INSERT
declaração, porque (além do desempenho) isso não é seguro simultaneamente: entre você INSERT
e sua SELECT
outra sessão pode ter inserido outro registro.
SELECT max(id)
infelizmente não faz o trabalho assim que você começa a excluir linhas.
1,2,3,4,5
e excluir as linhas 4 e 5, o último ID inserido ainda é 5, mas max()
retorna 3.
RETURNING id;
para inserir isso em outra tabela seria bem-vinda!
RETURNING id
dentro de um script SQL alimentado para a psql
ferramenta de linha de comando?
Consulte a cláusula RETURNING da instrução INSERT . Basicamente, o INSERT funciona como uma consulta e devolve o valor que foi inserido.
insert into names (firstname, lastname) values ('john', 'smith') returning id;
, então ele simplesmente saídas id como se você correu select id from names where id=$lastid
diretamente. Se você deseja salvar o retorno em uma variável , insert into names (firstname, lastname) values ('john', 'smith') returning id into other_variable;
se a declaração que contém o retorno é a última em uma função , o ID sendo returning
retornado é retornado pela função como um todo.
você pode usar a cláusula RETURNING na instrução INSERT, da seguinte maneira
wgzhao=# create table foo(id int,name text);
CREATE TABLE
wgzhao=# insert into foo values(1,'wgzhao') returning id;
id
----
1
(1 row)
INSERT 0 1
wgzhao=# insert into foo values(3,'wgzhao') returning id;
id
----
3
(1 row)
INSERT 0 1
wgzhao=# create table bar(id serial,name text);
CREATE TABLE
wgzhao=# insert into bar(name) values('wgzhao') returning id;
id
----
1
(1 row)
INSERT 0 1
wgzhao=# insert into bar(name) values('wgzhao') returning id;
id
----
2
(1 row)
INSERT 0
A resposta de Leonbloy é bastante completa. Eu acrescentaria apenas o caso especial em que é necessário obter o último valor inserido de uma função PL / pgSQL em que a OPÇÃO 3 não se encaixa exatamente.
Por exemplo, se tivermos as seguintes tabelas:
CREATE TABLE person(
id serial,
lastname character varying (50),
firstname character varying (50),
CONSTRAINT person_pk PRIMARY KEY (id)
);
CREATE TABLE client (
id integer,
CONSTRAINT client_pk PRIMARY KEY (id),
CONSTRAINT fk_client_person FOREIGN KEY (id)
REFERENCES person (id) MATCH SIMPLE
);
Se precisarmos inserir um registro de cliente, devemos nos referir a um registro de pessoa. Mas digamos que desejamos criar uma função PL / pgSQL que insira um novo registro no cliente, mas também cuide da inserção do novo registro de pessoa. Para isso, devemos usar uma pequena variação da OPÇÃO 3 de leonbloy:
INSERT INTO person(lastname, firstname)
VALUES (lastn, firstn)
RETURNING id INTO [new_variable];
Observe que existem duas cláusulas INTO. Portanto, a função PL / pgSQL seria definida como:
CREATE OR REPLACE FUNCTION new_client(lastn character varying, firstn character varying)
RETURNS integer AS
$BODY$
DECLARE
v_id integer;
BEGIN
-- Inserts the new person record and retrieves the last inserted id
INSERT INTO person(lastname, firstname)
VALUES (lastn, firstn)
RETURNING id INTO v_id;
-- Inserts the new client and references the inserted person
INSERT INTO client(id) VALUES (v_id);
-- Return the new id so we can use it in a select clause or return the new id into the user application
RETURN v_id;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
Agora podemos inserir os novos dados usando:
SELECT new_client('Smith', 'John');
ou
SELECT * FROM new_client('Smith', 'John');
E obtemos o ID recém-criado.
new_client
integer
----------
1
Veja o exemplo abaixo
CREATE TABLE users (
-- make the "id" column a primary key; this also creates
-- a UNIQUE constraint and a b+-tree index on the column
id SERIAL PRIMARY KEY,
name TEXT,
age INT4
);
INSERT INTO users (name, age) VALUES ('Mozart', 20);
Para obter o último ID inserido, use-o na tabela "user" seq nome da coluna "id"
SELECT currval(pg_get_serial_sequence('users', 'id'));
SELECT CURRVAL(pg_get_serial_sequence('my_tbl_name','id_col_name'))
Você precisa fornecer o nome da tabela e o nome da coluna, é claro.
Isso será para a sessão / conexão atual http://www.postgresql.org/docs/8.3/static/functions-sequence.html
Tente o seguinte:
select nextval('my_seq_name'); // Returns next value
Se isso retornar 1 (ou qualquer que seja o valor inicial da sua sequência), redefina a sequência novamente para o valor original, passando o sinalizador falso:
select setval('my_seq_name', 1, false);
De outra forma,
select setval('my_seq_name', nextValue - 1, true);
Isso restaurará o valor da sequência para o estado original e "setval" retornará com o valor da sequência que você está procurando.
O Postgres possui um mecanismo embutido para o mesmo, que na mesma consulta retorna o ID ou o que você deseja que a consulta retorne. aqui está um exemplo. Considere que você criou uma tabela que possui 2 colunas column1 e column2 e deseja que a coluna1 seja retornada após cada inserção.
# create table users_table(id serial not null primary key, name character varying);
CREATE TABLE
#insert into users_table(name) VALUES ('Jon Snow') RETURNING id;
id
----
1
(1 row)
# insert into users_table(name) VALUES ('Arya Stark') RETURNING id;
id
----
2
(1 row)
Eu tive esse problema com Java e Postgres. Corrigi-o atualizando uma nova versão do Connector-J.
postgresql-9.2-1002.jdbc4.jar
https://jdbc.postgresql.org/download.html : Versão 42.2.12