Як у PostgreSQL я можу отримати останній ідентифікатор, вставлений у таблицю?
У MS SQL є SCOPE_IDENTITY ().
Будь ласка, не радить мені використовувати щось подібне:
select max(id) from table
Як у PostgreSQL я можу отримати останній ідентифікатор, вставлений у таблицю?
У MS SQL є SCOPE_IDENTITY ().
Будь ласка, не радить мені використовувати щось подібне:
select max(id) from table
Відповіді:
( tl;dr
: goto варіант 3: ВСТАВИТИ З ПОВЕРНЕННЯМ)
Нагадаємо, що у postgresql не існує поняття "id" для таблиць, а лише послідовності (які зазвичай, але не обов'язково, використовуються як значення за замовчуванням для сурогатних первинних ключів, із ПЕРЕКЛЮЧЕННЯМ Псевдосерійного типу).
Якщо вам цікаво отримати ідентифікатор щойно вставленого рядка, є кілька способів:
Варіант 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'));
Caveat: 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
замість одного з 3 вищезазначених варіантів, щоб отримати ідентифікатор, щойно генерується вашим INSERT
висловлюванням, оскільки (крім продуктивності) це не є одночасно безпечним: між вашим INSERT
та вашим SELECT
іншим сеансом, можливо, було б вставлено інший запис.
SELECT max(id)
на жаль, не виконує цю роботу, як тільки ви почнете видаляти рядки.
1,2,3,4,5
та видалення рядків 4 і 5, останній вставлений ідентифікатор ще 5, але max()
повертається 3.
RETURNING id;
вставити це в іншу таблицю, буде вітатися!
RETURNING id
сценарій SQL, що подається на інструмент psql
командного рядка?
Див. Пункт ПОВЕРНЕННЯ оператора 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, де OPTION 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 (або що є початковим значенням для вашої послідовності), то скиньте послідовність назад до початкового значення, передаючи помилковий прапор:
select setval('my_seq_name', 1, false);
Інакше
select setval('my_seq_name', nextValue - 1, true);
Це відновить значення послідовності до початкового стану, а "setval" повернеться зі значенням послідовності, яку ви шукаєте.
Postgres має вбудований механізм для того ж, який у тому самому запиті повертає ідентифікатор або все, що ви хочете, щоб запит повертався. ось приклад. Подумайте, у вас створена таблиця, яка містить 2 стовпці колонки1 та стовпця2, і ви хочете, щоб стовпець1 повертався після кожного вставки.
# 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