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

Как лучше всего получить IDENTITY вставленного ряда?

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

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

вопрос задан 3.09.2008
Oded
401142 репутация

11 ответов


  • 0 рейтинг

    Лучший (читай: самый безопасный) способ получения идентификатора вновь вставленной строки - использование предложения 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)
    
    ответ дан Ian Kemp, с репутацией 15920, 29.04.2013
  • 0 рейтинг

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

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

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

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

    Выход

    ID
    2
    3
    4
    
    ответ дан MarredCheese, с репутацией 1886, 6.06.2018
  • 0 рейтинг

    MSDN

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

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

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

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

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

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

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

    ответ дан bdukes, с репутацией 110390, 3.09.2008
  • 0 рейтинг

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

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

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

    ответ дан Guy Starbuck, с репутацией 18865, 3.09.2008
  • 0 рейтинг

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

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

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

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

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

    ответ дан Orion Edwards, с репутацией 83341, 3.09.2008
  • 0 рейтинг

    Когда вы используете 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 или более поздней версии.

    ответ дан Ian Boyd, с репутацией 114699, 4.11.2016
  • 0 рейтинг

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

    ответ дан erikkallen, с репутацией 25464, 9.10.2009
  • 0 рейтинг

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

    IDENT_CURRENT('tableName')
    
    ответ дан Khan Ataur Rahman, с репутацией 16, 31.12.2017
  • 0 рейтинг

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

    , например (взято из следующей статьи 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
    
    ответ дан Orry, с репутацией 1788, 20.05.2011
  • 0 рейтинг

    Добавить

    SELECT CAST(scope_identity() AS int);
    

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

    NewId = command.ExecuteScalar()
    

    найдет его.

    ответ дан Jim, с репутацией 211, 30.03.2015