Как в PostgreSQL получить последний идентификатор, вставленный в таблицу?
В MS SQL есть SCOPE_IDENTITY ().
Пожалуйста, не советуйте мне использовать что-то вроде этого:
select max(id) from table
Как в PostgreSQL получить последний идентификатор, вставленный в таблицу?
В MS SQL есть SCOPE_IDENTITY ().
Пожалуйста, не советуйте мне использовать что-то вроде этого:
select max(id) from table
Ответы:
( tl;dr
: переход к варианту 3: вставка с возвратом)
Напомним, что в postgresql отсутствует концепция «id» для таблиц, а только последовательности (которые обычно, но не обязательно, используются в качестве значений по умолчанию для суррогатных первичных ключей с псевдотипом SERIAL ).
Если вы заинтересованы в получении идентификатора недавно вставленной строки, есть несколько способов:
Вариант 1: CURRVAL(<sequence name>);
.
Например:
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
SELECT currval('persons_id_seq');
Имя последовательности должно быть известно, оно действительно произвольно; в этом примере мы предполагаем, что в таблице persons
есть id
столбец, созданный с SERIAL
псевдотипом. Чтобы не полагаться на это и чувствовать себя более чистым, вы можете использовать вместо этого pg_get_serial_sequence
:
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
SELECT currval(pg_get_serial_sequence('persons','id'));
Предостережение: currval()
работает только после INSERT
(который выполнен nextval()
), в том же сеансе .
Вариант 2: LASTVAL();
Это похоже на предыдущее, только в том, что вам не нужно указывать имя последовательности: оно ищет самую последнюю измененную последовательность (всегда внутри вашего сеанса, то же предупреждение, что и выше).
Оба CURRVAL
и LASTVAL
полностью безопасны одновременно. Поведение последовательности в PG спроектировано таким образом, что другой сеанс не будет мешать, поэтому нет риска возникновения условий гонки (если другой сеанс вставит другую строку между моим INSERT и моим SELECT, я все равно получу правильное значение).
Однако у них есть тонкая потенциальная проблема. Если в базе данных есть какой-то TRIGGER (или RULE), который при вставке в persons
таблицу делает дополнительные вставки в другие таблицы ... тогда LASTVAL
, вероятно, даст нам неправильное значение. Проблема может даже случиться CURRVAL
, если дополнительные вставки выполняются в одну и ту же persons
таблицу (это гораздо реже, но риск все еще существует).
Вариант 3: INSERT
сRETURNING
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John') RETURNING id;
Это самый чистый, эффективный и безопасный способ получить удостоверение личности. Это не имеет никакого риска предыдущего.
Недостатки? Почти ничего: вам может понадобиться изменить способ вызова оператора INSERT (в худшем случае, возможно, ваш уровень API или DB не ожидает, что INSERT вернет значение); это не стандартный SQL (кого это волнует); это доступно с Postgresql 8.2 (декабрь 2006 ...)
Вывод: если можете, перейдите к варианту 3. В другом месте предпочтите 1.
Примечание: все эти методы бесполезны, если вы намерены получить последний вставленный идентификатор глобально (не обязательно с помощью вашего сеанса). Для этого вы должны прибегнуть к SELECT max(id) FROM table
(конечно, это не будет читать незафиксированные вставки из других транзакций).
И наоборот, вы никогда не должны использовать SELECT max(id) FROM table
вместо этого один из трех вариантов выше, чтобы получить идентификатор, только что сгенерированный вашим INSERT
оператором, потому что (кроме производительности) это не безопасно одновременно: между вашим INSERT
и вашим SELECT
другим сеансом может быть вставлена другая запись.
SELECT max(id)
к сожалению, не выполняет работу, как только вы начинаете удалять строки.
1,2,3,4,5
и вы удалите строки 4 и 5, последний вставленный идентификатор по-прежнему 5, но max()
возвращает 3.
RETURNING id;
для вставки в другую таблицу, будет приветствоваться!
RETURNING id
в сценарии SQL, поданного в psql
инструмент командной строки?
Смотрите предложение RETURNING оператора INSERT . По сути, INSERT удваивается как запрос и возвращает вам значение, которое было вставлено.
insert into names (firstname, lastname) values ('john', 'smith') returning id;
то он просто выводит id так же, как если бы вы работали select id from names where id=$lastid
напрямую. Если вы хотите сохранить возврат в переменную aa , то insert into names (firstname, lastname) values ('john', 'smith') returning id into other_variable;
если оператор, содержащий возвращение, является последним оператором в функции , то редактируемый идентификатор returning
возвращается функцией в целом.
Вы можете использовать предложение RETURNING в операторе INSERT, как показано ниже
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
Ответ Леонблоя довольно полный. Я бы добавил только тот особый случай, когда нужно получить последнее вставленное значение из функции PL / pgSQL, где ОПЦИЯ 3 не подходит точно.
Например, если у нас есть следующие таблицы:
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
);
Если нам нужно вставить запись клиента, мы должны обратиться к записи человека. Но скажем, мы хотим разработать функцию PL / pgSQL, которая вставляет новую запись в клиент, но также заботится о вставке новой записи о человеке. Для этого мы должны использовать небольшое изменение ВАРИАНТА 3 leonbloy:
INSERT INTO person(lastname, firstname)
VALUES (lastn, firstn)
RETURNING id INTO [new_variable];
Обратите внимание, что есть два предложения INTO. Следовательно, функция PL / pgSQL будет определена так:
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;
Теперь мы можем вставить новые данные, используя:
SELECT new_client('Smith', 'John');
или
SELECT * FROM new_client('Smith', 'John');
И мы получаем недавно созданный идентификатор.
new_client
integer
----------
1
Смотрите пример ниже
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);
Затем для получения последнего вставленного идентификатора используйте это для таблицы "user". Seq имя столбца "id"
SELECT currval(pg_get_serial_sequence('users', 'id'));
SELECT CURRVAL(pg_get_serial_sequence('my_tbl_name','id_col_name'))
Вам необходимо указать имя таблицы и название столбца, конечно.
Это будет для текущего сеанса / подключения http://www.postgresql.org/docs/8.3/static/functions-sequence.html.
Попробуй это:
select nextval('my_seq_name'); // Returns next value
Если это вернет 1 (или что-то еще из start_value для вашей последовательности), тогда верните последовательность обратно к исходному значению, передав флаг false:
select setval('my_seq_name', 1, false);
В противном случае,
select setval('my_seq_name', nextValue - 1, true);
Это восстановит значение последовательности в исходное состояние, а «setval» вернет значение последовательности, которое вы ищете.
Postgres имеет встроенный механизм для этого, который в том же запросе возвращает идентификатор или все, что вы хотите, чтобы запрос возвращал. вот пример. Предположим, у вас есть созданная таблица, в которой есть 2 столбца column1 и column2, и вы хотите, чтобы column1 возвращалась после каждой вставки.
# 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)
У меня была эта проблема с Java и Postgres. Я исправил это, обновив новую версию Connector-J.
PostgreSQL-9.2-1002.jdbc4.jar
https://jdbc.postgresql.org/download.html : версия 42.2.12