Лучший способ получить идентичность вставленной строки? - PullRequest
995 голосов
/ 04 сентября 2008

Каков наилучший способ получить IDENTITY вставленной строки?

Я знаю о @@IDENTITY и IDENT_CURRENT и SCOPE_IDENTITY, но не понимаю плюсы и минусы каждого из них.

Может кто-нибудь объяснить, почему и когда я должен использовать каждый из них?

Ответы [ 13 ]

1288 голосов
/ 04 сентября 2008
  • @@IDENTITY возвращает последнее значение идентификатора, сгенерированное для любой таблицы в текущем сеансе, во всех областях. Вы должны быть осторожны здесь , так как это выходит за рамки. Вы можете получить значение из триггера вместо текущего оператора.

  • SCOPE_IDENTITY() возвращает последнее значение идентификатора, созданное для любой таблицы в текущем сеансе и текущей области. Как правило, что вы хотите использовать .

  • IDENT_CURRENT('tableName') возвращает последнее значение идентификатора, сгенерированное для конкретной таблицы в любом сеансе и любой области. Это позволяет вам указать, из какой таблицы вы хотите получить значение, в случае, если два приведенных выше не совсем то, что вам нужно ( очень редко ). Кроме того, как заметил * Гай Старбак : «Вы можете использовать это, если хотите получить текущее значение IDENTITY для таблицы, в которую вы не вставили запись.»

  • Предложение 1034 * оператора INSERT позволит вам получить доступ к каждой строке, которая была вставлена ​​с помощью этого оператора. Поскольку он ограничен конкретным оператором, он более простой , чем другие функции выше. Тем не менее, он немного более подробный (вам нужно вставить в таблицу переменную / временную таблицу, а затем запросить это), и это дает результаты даже в случае ошибки, когда оператор откатывается. Тем не менее, если в вашем запросе используется план параллельного выполнения, это гарантированный метод для получения идентификатора (за исключением отключения параллелизма). Однако он выполняется до срабатывания и не может использоваться для возврата сгенерированных триггером значений.

165 голосов
/ 20 мая 2011

Я полагаю, что наиболее безопасный и точный метод получения вставленного идентификатора - использование предложения output.

например (взят из следующей статьи MSDN )

USE AdventureWorks2008R2;
GO
DECLARE @MyTableVar table( NewScrapReasonID smallint,
                           Name varchar(50),
                           ModifiedDate datetime);
INSERT Production.ScrapReason
    OUTPUT INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate
        INTO @MyTableVar
VALUES (N'Operator error', GETDATE());

--Display the result set of the table variable.
SELECT NewScrapReasonID, Name, ModifiedDate FROM @MyTableVar;
--Display the result set of the table.
SELECT ScrapReasonID, Name, ModifiedDate 
FROM Production.ScrapReason;
GO
102 голосов
/ 04 сентября 2008

Я говорю то же самое, что и другие парни, так что все правы, я просто пытаюсь прояснить это.

@@IDENTITY возвращает идентификатор последней вещи, которая была вставлена ​​при подключении вашего клиента к базе данных.
В большинстве случаев это работает нормально, но иногда запускается триггер и вставляется новая строка, о которой вы не знаете, и вы получаете идентификатор из этой новой строки вместо той, которую вы хотите

SCOPE_IDENTITY() решает эту проблему. Он возвращает идентификатор последней вещи, которую вы вставили в код SQL , которую вы отправили в базу данных. Если триггеры идут и создают дополнительные строки, они не приведут к возвращению неправильного значения. Hooray

IDENT_CURRENT возвращает последний идентификатор, который был вставлен кем-либо. Если какое-то другое приложение вставит еще одну строку в несчастное время, вы получите идентификатор этой строки вместо вашей.

Если вы хотите быть осторожным, всегда используйте SCOPE_IDENTITY(). Если вы придерживаетесь @@IDENTITY и кто-то решит добавить триггер позже, весь ваш код сломается.

62 голосов
/ 29 апреля 2013

Лучший (читай: самый безопасный) способ получения идентификатора вновь вставленной строки - использование предложения output:

create table TableWithIdentity
           ( IdentityColumnName int identity(1, 1) not null primary key,
             ... )

-- type of this table's column must match the type of the
-- identity column of the table you'll be inserting into
declare @IdentityOutput table ( ID int )

insert TableWithIdentity
     ( ... )
output inserted.IdentityColumnName into @IdentityOutput
values
     ( ... )

select @IdentityValue = (select ID from @IdentityOutput)
21 голосов
/ 30 марта 2015

Добавить

SELECT CAST(scope_identity() AS int);

до конца вашего оператора вставки SQL, затем

NewId = command.ExecuteScalar()

найдет его.

14 голосов
/ 04 сентября 2008

* MSDN 1002 *

@@ IDENTITY, SCOPE_IDENTITY и IDENT_CURRENT - аналогичные функции, так как они возвращают последнее значение, вставленное в столбец IDENTITY таблицы.

@@ IDENTITY и SCOPE_IDENTITY будут возвращать последнее значение идентификатора, сгенерированное в любой таблице в текущем сеансе. Однако SCOPE_IDENTITY возвращает значение только в пределах текущей области; @@ IDENTITY не ограничивается конкретной областью действия.

IDENT_CURRENT не ограничен областью действия и сессией; он ограничен указанной таблицей. IDENT_CURRENT возвращает значение идентификатора, созданное для конкретной таблицы в любом сеансе и любой области. Для получения дополнительной информации см. IDENT_CURRENT.

  • IDENT_CURRENT - это функция, которая принимает таблицу в качестве аргумента.
  • @@ IDENTITY может дать неверный результат, если у вас есть триггер на столе
  • SCOPE_IDENTITY является вашим героем большую часть времени.
13 голосов
/ 04 ноября 2016

Когда вы используете Entity Framework, он внутренне использует технику OUTPUT для возврата вновь вставленного значения идентификатора

DECLARE @generated_keys table([Id] uniqueidentifier)

INSERT INTO TurboEncabulators(StatorSlots)
OUTPUT inserted.TurboEncabulatorID INTO @generated_keys
VALUES('Malleable logarithmic casing');

SELECT t.[TurboEncabulatorID ]
FROM @generated_keys AS g 
   JOIN dbo.TurboEncabulators AS t 
   ON g.Id = t.TurboEncabulatorID 
WHERE @@ROWCOUNT > 0

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

Примечание: я понятия не имею, почему EF внутренне соединяет эфемерную таблицу с реальной таблицей (при каких обстоятельствах эти две пары не совпадают).

Но это то, что делает EF.

Этот метод (OUTPUT) доступен только в SQL Server 2008 или более поздней версии.

13 голосов
/ 04 сентября 2008

@@ IDENTITY - это последний идентификатор, вставленный с использованием текущего соединения SQL. Это хорошее значение для возврата из хранимой процедуры вставки, где вам просто нужно вставить идентификатор для новой записи, и не волнует, будет ли добавлено больше строк после этого.

SCOPE_IDENTITY - это последний идентификатор, вставленный с использованием текущего соединения SQL, и в текущей области действия, то есть, если после вставки была вставлена ​​вторая IDENTITY, основанная на триггере, она не отражено в SCOPE_IDENTITY, только вставка, которую вы выполнили. Честно говоря, у меня никогда не было причин использовать это.

IDENT_CURRENT (имя таблицы) является последней вставленной идентификацией независимо от соединения или области действия. Вы можете использовать это, если хотите получить текущее значение IDENTITY для таблицы, в которую вы не вставили запись.

10 голосов
/ 06 июня 2018

Я не могу говорить с другими версиями SQL Server, но в 2012 году вывод напрямую работает просто отлично. Вам не нужно беспокоиться о временной таблице.

INSERT INTO MyTable
OUTPUT INSERTED.ID
VALUES (...)

Кстати, эта техника также работает при вставке нескольких строк.

INSERT INTO MyTable
OUTPUT INSERTED.ID
VALUES
    (...),
    (...),
    (...)

выход

ID
2
3
4
8 голосов
/ 10 октября 2009

ВСЕГДА используйте scope_identity (), НИКОГДА больше не нужно ничего.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...