En PostgreSQL, ¿cómo puedo insertar la última identificación en una tabla?
En MS SQL hay SCOPE_IDENTITY ().
Por favor no me aconsejen usar algo como esto:
select max(id) from table
En PostgreSQL, ¿cómo puedo insertar la última identificación en una tabla?
En MS SQL hay SCOPE_IDENTITY ().
Por favor no me aconsejen usar algo como esto:
select max(id) from table
Respuestas:
( tl;dr
: goto opción 3: INSERTAR con RETORNO)
Recuerde que en postgresql no hay un concepto de "id" para las tablas, solo secuencias (que normalmente se usan, pero no necesariamente, como valores predeterminados para las claves primarias sustitutas, con el pseudotipo SERIAL ).
Si está interesado en obtener la identificación 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, suponemos que la tabla persons
tiene una id
columna creada con el SERIAL
pseudotipo. Para evitar confiar en esto y sentirse más limpio, puede usar en su lugar pg_get_serial_sequence
:
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 se ha ejecutado nextval()
), en la misma sesión .
Opcion 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).
Ambos CURRVAL
y LASTVAL
son totalmente concurrentes seguros. El comportamiento de la secuencia en PG está diseñado para que una sesión diferente no interfiera, por lo que no hay riesgo de condiciones de carrera (si otra sesión inserta otra fila entre mi INSERT y mi SELECT, aún obtengo mi valor correcto).
Sin embargo, tienen un problema potencial sutil. Si la base de datos tiene algún DISPARADOR (o REGLA) que, al insertarlo en la persons
tabla, hace algunas inserciones adicionales en otras tablas ... entonces LASTVAL
probablemente nos dará el valor incorrecto. El problema puede suceder incluso CURRVAL
si las inserciones adicionales se realizan en la misma persons
tabla (esto es mucho menos habitual, pero el riesgo aún existe).
Opción 3: INSERT
conRETURNING
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 instrucción INSERT (en el peor de los casos, quizás su capa API o DB 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 otro lugar, 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 por su sesión). Para esto, debe recurrir a SELECT max(id) FROM table
(por supuesto, esto no leerá inserciones no confirmadas de otras transacciones).
Por el contrario, nunca debe utilizar SELECT max(id) FROM table
una de las 3 opciones anteriores, para obtener la identificación que acaba de generar su INSERT
declaración, porque (aparte del rendimiento) esto no es concurrentemente seguro: entre usted INSERT
y su SELECT
otra sesión podría haber insertado otro registro.
SELECT max(id)
desafortunadamente, tampoco hace el trabajo tan pronto como comienza a eliminar filas.
1,2,3,4,5
y elimina las filas 4 y 5, la última ID insertada sigue siendo 5, pero max()
devuelve 3.
RETURNING id;
para insertar esto en otra tabla sería bienvenida!
RETURNING id
dentro de un script SQL alimentado a la psql
herramienta de línea de comando?
Consulte la cláusula RETURNING de la declaración INSERT . Básicamente, INSERT funciona como una consulta y le devuelve el valor que se insertó.
insert into names (firstname, lastname) values ('john', 'smith') returning id;
entonces simplemente genera la identificación como si se ejecutara select id from names where id=$lastid
directamente. Si desea guardar el retorno en una variable aa , entonces, insert into names (firstname, lastname) values ('john', 'smith') returning id into other_variable;
si la declaración que contiene el retorno es la última declaración en una función , returning
la función en su conjunto devuelve el ID que se está editando.
puede usar la cláusula RETURNING en la instrucción INSERT, como lo 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 uno necesita obtener el último valor insertado dentro de una función PL / pgSQL donde la OPCIÓN 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 supongamos que queremos diseñar una función PL / pgSQL que inserte un nuevo registro en el cliente pero que 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 identificación recién creada.
new_client
integer
----------
1
Ver 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 "user" seq nombre de columna "id"
SELECT currval(pg_get_serial_sequence('users', 'id'));
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
Prueba esto:
select nextval('my_seq_name'); // Returns next value
Si esto devuelve 1 (o lo que sea el valor inicial de su secuencia), restablezca la secuencia nuevamente 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.
Postgres tiene un mecanismo incorporado para el mismo, que en la misma consulta devuelve la identificación 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)
Tuve este problema con Java y Postgres. Lo arreglé actualizando una nueva versión de Connector-J.
postgresql-9.2-1002.jdbc4.jar
https://jdbc.postgresql.org/download.html : Versión 42.2.12