Лучший способ получить идентификатор вставленной строки?

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

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

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

11 ответов


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

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

  • IDENT_CURRENT('tableName') возвращает последнее значение идентификатора, созданное для указанной таблицы в любом сеансе и области. Это позволяет указать, из какой таблицы вы хотите получить значение, если два выше не совсем то, что вам нужно (очень редко). Также, как @Парень Старбак упомянуто: "вы можете использовать это, если хотите получить текущее значение идентификатора для таблицы, в которую вы не вставили запись в."

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


Я считаю, что самый безопасный и точный метод извлечения вставленного идентификатора будет использовать предложение 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

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

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

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

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

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


лучший (read: safest) способ получить идентификатор вновь вставленной строки-использовать 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)

добавить

SELECT CAST(scope_identity() AS int);

до конца инструкции insert sql, затем

NewId = command.ExecuteScalar()

восстановит его.


MSDN

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

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

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

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

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

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

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


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

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 или новее.


всегда используйте scope_identity (), больше ничего не нужно.


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

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

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

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

выход

ID
2
3
4

после инструкции Insert вам нужно добавить это. И убедитесь в имени таблицы, в которую вставляются данные.Вы получите текущую строку no where row, на которую только что повлияла ваша инструкция insert.

IDENT_CURRENT('tableName')