В PostgreSQL, как я вставлял последний идентификатор в таблицу?
В MS SQL там является SCOPE_IDENTITY ().
Не советуйте мне использовать что-то вроде этого:
select max(id) from table
( tl;dr
: перейдите к варианту 3: INSERT с RETURNING)
Напомним, что в postgresql нет понятия "id" для таблиц, только последовательности (которые обычно, но не обязательно используются как значения по умолчанию для суррогатных первичных ключей, с псевдо-типом SERIAL).
Если вас интересует получение id только что вставленного ряда, есть несколько способов:
Вариант 1: CURRVAL(<имя последовательности>);
.
Например:
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;
Это самый чистый, эффективный и безопасный способ получения id. У него нет ни одного из рисков предыдущего.
Недостатки? Почти нет: возможно, вам придется изменить способ вызова оператора INSERT (в худшем случае, возможно, ваш API или уровень БД не ожидает, что INSERT вернет значение); это не стандартный SQL (кого это волнует); он доступен с Postgresql 8.2 (Dec 2006...)
Заключение: Если есть возможность, выбирайте вариант 3. В других случаях предпочтите 1.
Примечание: все эти методы бесполезны, если вы хотите получить последний вставленный id глобально (не обязательно по вашей сессии). Для этого вы должны прибегнуть к SELECT max(id) FROM table
(конечно, это не позволит прочитать незафиксированные вставки из других транзакций).
И наоборот, вы должны никогда не использовать SELECT max(id) FROM table
вместо одного из 3 вариантов выше, чтобы получить id, только что созданный вашим INSERT
оператором, потому что (помимо производительности) это небезопасно для одновременной работы: между вашим INSERT
и вашим SELECT
другая сессия могла вставить другую запись.
Смотрите пункт RETURNING оператора INSERT. По сути, INSERT удваивает запрос и возвращает вам значение, которое было вставлено.
См. Пример ниже
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);
Затем для получения последнего вставленного идентификатора используйте это для таблицы "пользователь" имя столбца 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