2009-04-08 8 views
5

Digamos que tengo un procedimiento almacenado con esto en su cuerpo:T-SQL EXEC y alcance

EXEC 'INSERT INTO ' + quotename(@table) ' blah...' 
SELECT IDENT_CURRENT('' + @table + '') 

Es IDENT_CURRENT() garantizado para conseguir la identidad de esa fila insertada en el EXEC? IDENT_CURRENT() "devuelve el último valor de identidad generado para una tabla específica en cualquier sesión y cualquier ámbito", pero el alcance es diferente dentro del EXEC que el procedimiento almacenado, ¿verdad?

Quiero asegurarme de que si se llama al procedimiento almacenado varias veces a la vez, se SELECCIONE la identidad correcta.

EDIT: ¿O tengo que hacer tanto el INSERT y SELECT en el EXEC, así:

declare @insert nvarchar 
set @insert = 
    'INSERT INTO ' + quotename(@table) ' blah...' + 
    'SELECT IDENT_CURRENT(''' + @table + ''')' 
EXEC @insert 

Y si ese es el caso, ¿Cómo se selecciona el resultado de la EXEC si quiero continuar con más código en T-SQL? Como esto (aunque obviamente no es correcta):

declare @insert nvarchar 
set @insert = 
    'INSERT INTO ' + quotename(@table) ' blah...' + 
    'SELECT IDENT_CURRENT(''' + @table + ''')' 

declare @ident int 
set @ident = EXEC @insert 

-- more code 
SELECT * FROM blah 

ACTUALIZACIÓN: En el primer fragmento, si selecciono SCOPE_IDENTITY() en lugar de utilizar IDENT_CURRENT(), NULL es devuelto por el SELECT. :(

Respuesta

6

Trate

EXEC 'INSERT INTO ' + quotename(@table) ' blah...; SELECT @@IDENTITY' 

o mejor, de acuerdo con this

EXEC 'INSERT INTO ' + quotename(@table) ' blah...; SELECT SCOPE_IDENTITY()' 
+0

Sugerimos que use la segunda. @@ Identidad casi nunca debe usarse ya que a menudo no dará resultados correctos. Felicitaciones por reconocer que la identidad del ámbito debe estar en la declaración del ejecutivo. – HLGEM

1

Creo SCOPE_IDENTITY() es lo que está buscando, lo que le dará la más reciente en identificar el alcance actual.

4

De acuerdo con los documentos T-SQL de Microsoft:

IDENT_CURRENT es similar al SQL Funciones de identidad del servidor 2000 SCOPE_IDENTITY y @@ IDENTITY. Todas las funciones de devuelven los últimos valores de identidad generados por última vez. Sin embargo, el alcance y sesión en la que la última se define en cada una de estas funciones difieren:

IDENT_CURRENT devuelve el último valor de identidad generado para una tabla específica en cualquier sesión y cualquier alcance.

@@ IDENTITY devuelve el último valor de identidad generado para cualquier tabla en la sesión actual , en todos los ámbitos.

SCOPE_IDENTITY devuelve el último valor de identidad generado para cualquier tabla en la sesión actual y la corriente alcance.

Así que yo diría, no, hace IDENT_CURRENT no garantía para dar vuelta el valor correcto. Podría ser el último valor de IDENTIDAD insertado en una sesión diferente.

Me aseguraría de usar SCOPE_IDENTITY en su lugar, eso debería funcionar de manera confiable.

Marc

2

http://blog.sqlauthority.com/2009/03/24/sql-server-2008-scope_identity-bug-with-multi-processor-parallel-plan-and-solution/

Hay un error en SCOPE_IDENTITY() he cambiado mis procedimientos almacenados a la metodología utilizada para recuperar los valores por defecto de una inserción:

declare @TheNewIds table (Id bigint, Guid uniqueidentifier) 
insert [dbo].[TestTable] output inserted.Id, inserted.Guid into @TheNewIds 
values (default); 
select @Id = [Id], @Guid = [Guid] from @TheNewIds; 
0

Me gustaría introducir mi solución favorita usando la palabra clave OUTPUT. Como INSERT puede admitir varias filas a la vez, quisiéramos conocer las identidades insertadas. Aquí va:


-- source table 
if object_id('Source') is not null drop table Source 
create table Source 
(
    Value datetime 
) 
-- populate source 
insert Source select getdate() 
waitfor delay '00:00.1' 
insert Source select getdate() 
waitfor delay '00:00.1' 
insert Source select getdate() 
select * from Source -- test 
-- destination table 
if object_id('Destination') is null 
create table Destination 
(
    Id int identity(1, 1), 
    Value datetime 
) 
-- tracking table to keep all generated Id by insertion of table Destination 
if object_id('tempdb..#Track') is null 
create table #Track 
(
    Id int 
) 
else delete #Track 
-- copy source into destination, track the Id using OUTPUT 
insert Destination output inserted.Id into #Track select Value from Source 
select Id from #Track -- list out all generated Ids 

Continúe ejecutando esto varias veces para sentir cómo funciona.