last - Función PostgreSQL para el último ID insertado
select last value postgresql (10)
En PostgreSQL, ¿cómo puedo insertar la última ID en una tabla?
En MS SQL hay SCOPE_IDENTITY ().
Por favor no me aconsejen usar algo como esto:
select max(id) from table
( tl;dr
: goto opción 3: INSERTAR con DEVOLUCIÓN)
Recuerde que en postgresql no existe un concepto de "id" para las tablas, solo las secuencias (que normalmente, pero no necesariamente, se usan como valores predeterminados para las claves primarias sustitutas, con el pseudo tipo SERIAL ).
Si está interesado en obtener el ID de una fila recién insertada, hay varias formas:
Opción 1: CURRVAL(<sequence name>);
.
Por ejemplo:
INSERT INTO persons (lastname,firstname) VALUES (''Smith'', ''John'');
SELECT currval(''persons_id_seq'');
El nombre de la secuencia debe ser conocido, es realmente arbitrario; en este ejemplo, asumimos que las persons
la tabla persons
una columna de id
creada con el pseudo-tipo SERIAL
. Para evitar confiar en esto y sentirse más limpio, puede usar pg_get_serial_sequence
en su lugar:
INSERT INTO persons (lastname,firstname) VALUES (''Smith'', ''John'');
SELECT currval(pg_get_serial_sequence(''persons'',''id''));
Advertencia: currval()
solo funciona después de un INSERT
(que ha ejecutado nextval()
), en la misma sesión .
Opción 2: LASTVAL();
Esto es similar al anterior, solo que no necesita especificar el nombre de la secuencia: busca la secuencia modificada más reciente (siempre dentro de su sesión, la misma advertencia que la anterior).
Tanto CURRVAL
como LASTVAL
son totalmente seguros a la vez. El comportamiento de la secuencia en PG está diseñado para que las diferentes sesiones no interfieran, por lo que no hay riesgo de condiciones de carrera (si otra sesión inserta otra fila entre mi INSERT y mi SELECT, todavía obtengo mi valor correcto).
Sin embargo, tienen un problema potencial sutil. Si la base de datos tiene algún TRIGGER (o REGLA) que, al insertarse en la tabla de persons
, hace algunas inserciones adicionales en otras tablas ... entonces LASTVAL
probablemente nos dará el valor incorrecto. El problema puede incluso ocurrir con CURRVAL
, si las inserciones adicionales se realizan en la misma tabla de persons
(esto es mucho menos habitual, pero el riesgo aún existe).
Opción 3: INSERT
con RETURNING
INSERT INTO persons (lastname,firstname) VALUES (''Smith'', ''John'') RETURNING id;
Esta es la forma más limpia, eficiente y segura de obtener la identificación. No tiene ninguno de los riesgos de lo anterior.
Inconvenientes? Casi ninguno: es posible que deba modificar la forma en que llama a su declaración INSERT (en el peor de los casos, tal vez su API o capa de base de datos no espera que un INSERT devuelva un valor); no es SQL estándar (a quién le importa); está disponible desde Postgresql 8.2 (diciembre de 2006 ...)
Conclusión: si puede, vaya a la opción 3. En otra parte, prefiera 1.
Nota: todos estos métodos son inútiles si tiene la intención de obtener la última identificación insertada globalmente (no necesariamente en su sesión). Para esto, debe recurrir a select max(id) from table
(por supuesto, esto no leerá las inserciones no confirmadas de otras transacciones).
Consulte la cláusula RETURNING de la INSERT . Básicamente, el INSERT se duplica como una consulta y le devuelve el valor insertado.
Para aquellos que necesitan obtener el registro de todos los datos, puede agregar
returning *
hasta el final de su consulta para obtener todos los objetos, incluido el ID.
Postgres tiene un mecanismo incorporado para el mismo, que en la misma consulta devuelve el ID o lo que quiera que devuelva la consulta. Aquí hay un ejemplo. Considere que tiene una tabla creada que tiene 2 columnas column1 y column2 y desea que se devuelva column1 después de cada inserción.
# 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)
Prueba esto:
select nextval(''my_seq_name''); // Returns next value
Si esto devuelve 1 (o cualquiera que sea el valor_inicial para su secuencia), entonces restablezca la secuencia al valor original, pasando el indicador falso:
select setval(''my_seq_name'', 1, false);
De otra manera,
select setval(''my_seq_name'', nextValue - 1, true);
Esto restaurará el valor de secuencia al estado original y "setval" regresará con el valor de secuencia que está buscando.
Si solo necesita recuperar la última identificación insertada sin insertar nada, puede usar el siguiente ejemplo
SELECT id FROM users ORDER BY id DESC LIMIT 1;
La esperanza puede ayudar.
Vea el siguiente ejemplo
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);
Luego, para obtener la última identificación insertada, use esto para la tabla "usuario" seq nombre de columna "identificación"
SELECT currval(pg_get_serial_sequence(''users'', ''id''));
puede usar la cláusula RETURNING en la instrucción INSERT, al igual que la siguiente
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
La respuesta de Leonbloy es bastante completa. Solo agregaría el caso especial en el que se necesita obtener el último valor insertado desde una función PL / pgSQL donde OPTION 3 no se ajusta exactamente.
Por ejemplo, si tenemos las siguientes tablas:
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
);
Si necesitamos insertar un registro de cliente, debemos referirnos a un registro de persona. Pero digamos que queremos diseñar una función PL / pgSQL que inserte un nuevo registro en el cliente pero también se encargue de insertar el nuevo registro de persona. Para eso, debemos usar una ligera variación de la OPCIÓN 3 de leonbloy:
INSERT INTO person(lastname, firstname)
VALUES (lastn, firstn)
RETURNING id INTO [new_variable];
Tenga en cuenta que hay dos cláusulas INTO. Por lo tanto, la función PL / pgSQL se definiría 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;
Ahora podemos insertar los nuevos datos usando:
SELECT new_client(''Smith'', ''John'');
o
SELECT * FROM new_client(''Smith'', ''John'');
Y obtenemos la id recién creada.
new_client
integer
----------
1
SELECT CURRVAL(pg_get_serial_sequence(''my_tbl_name'',''id_col_name''))
Debe proporcionar el nombre de la tabla y el nombre de la columna, por supuesto.
Esto será para la sesión / conexión actual http://www.postgresql.org/docs/8.3/static/functions-sequence.html