Каков стандартный способ получения последнего идентификатора вставки? - PullRequest
7 голосов
/ 19 февраля 2011

Что такое стандарт SQL для получения последнего вставленного идентификатора? Если есть такая вещь.

mysql: LAST_INSERT_ID ()
postgresql: ... ВОЗВРАТ f_id
mssql: SCOPE_IDENTITY ()
... больше примеров здесь ...

Я имею в виду, все базы данных имеют разные реализации для этого, не существует стандарта для такой общей задачи?

Ответы [ 4 ]

9 голосов
/ 19 февраля 2011

См. Этот ответ Извлечение вставленного идентификатора строки в SQL

Короче говоря, не существует кросс-базы данных для этого, кроме MAX (ID), но это не гарантированный результати имеет много ловушек, например

  • другие вставки могут находиться между последней вставкой и максимальным запросом
  • не может использоваться с таблицами с высокими транзакциями (max выдаст блокировку чтения, специфичную для rdbmsметоды не читают ни из одной таблицы)

Стандарт ANSI, относящийся к идентификаторам / autonumber / auto_increment / sequence, впервые появился в SQL: 2003 , ожидая реализации всеми основными СУБД.Скорее всего, он будет напоминать последовательности Oracle / PostgreSQL.

Стандарт SQL: 2003 вносит незначительные изменения во все части SQL: 1999 (также известный как SQL3) и официально вводит несколько новых функций, таких как:

- генератор последовательностей, который допускает стандартизированные последовательности

Еще одно изменение в SQL: 2003 - это OUTPUT USING CLAUSE, но о нем очень мало информации.Sybase и SQL Server сделали с ним разные вещи, так что пока неясно, как это получится.SQL Server реализует его как

INSERT INTO TBL(..)
OUTPUT inserted.identity_col
INTO @sometablevar
VALUES(..)
3 голосов
/ 19 февраля 2011

Oracle и PostgreSQL поддерживают предложение RETURNING и используют объект, называемый последовательностью, для обеспечения автоматической последовательной нумерации.Следующая версия SQL Server, denali, настроена на поддержку последовательностей, но я не видел ни слова, будет ли Denali поддерживать предложение RETURNING.Другое средство получения текущего значения последовательности:

Oracle: sequence_name.CURRVAL 
PostgreSQL: CURRVAL('sequence_name')

DB2 поддерживает последовательностей и предложение RETURNING INTO .

SELECT MAX(auto_increment_column) ...это не рекомендуемая практика, потому что это ненадежно.В Oracle читатели (SELECT) не блокируются писателями (INSERT / UPDATE), поэтому значение не может быть гарантировано правильным.

Заключение

Я не знал, что Стандарт ANSI SQL: 2003 включает в себя использование последовательностей для автонумерации, но в настоящее время не существует согласованных средств для извлечения значения.

0 голосов
/ 19 февраля 2011

Один метод, вероятно, будет работать со всеми БД, и в тех случаях, когда последовательность не является простым инкрементным числом (например, существуют ранее существующие строки с высокими идентификаторами, поэтому вы не можете использовать MAX), это:

  1. Определите, каким будет следующий идентификатор, например, с помощью функции nextval или аналогичной.
  2. Вставьте строку, используя этот идентификатор.
  3. Используйте идентификатор для остальныхваших потребностей.
0 голосов
/ 19 февраля 2011

Это скорее разъяснение к нескольким комментариям, чем реальный новый ответ, но здесь оно подходит лучше.select max (id) работает нормально, пока клиент находится в сериализуемой транзакции.В pgsql вы можете доказать это себе.Откройте два сеанса psql и запустите его сначала с подтверждением чтения по умолчанию, а затем в сериализуемом:

p1: create table test (id serial);
p1 and p2: begin;
p1 and p2: set transaction isolation level serializable;
p1: insert into test values (DEFAULT);
p2: insert into test values (DEFAULT);
p1: select max(id) from test;
 1
p2: select max(id) from test;
 2
p2: commit;
p1: select max(id) from test;
 2

Однако с подтверждением чтения:

p1: create table test (id serial);
p1 and p2: begin;
p1 and p2: set transaction isolation level read committed;
p1: insert into test values (DEFAULT);
p2: insert into test values (DEFAULT);
p1: select max(id) from test;
 1
p2: select max(id) from test;
 2
p2: commit;
p1: select max(id) from test;
 1

Сериализированные транзакции с точки зрения производительности могутотрицательные воздействия или приводящие к неудачным транзакциям, которые необходимо откатить и повторить, и т. д.

Возврат или currval () - гораздо лучшие идеи.Однако говорить о том, что max (id) просто нельзя доверять, неверно, если выполняемая транзакция сериализуема.

...