scope_identity devuelve dbnull debido a en lugar de desencadenar

Tengo un lugar de gatillo en una mesa. El activador funciona bien, pero tenemos una aplicación en la que los usuarios pueden realizar una actualización masiva de la tabla a través de la interfaz de usuario. seleccione scope_identity devuelve nulo en ese caso. Ejecuté sql profiler para ver qué sucede en segundo plano cuando los usuarios realizan una actualización a través de la interfaz de usuario y obtuve esto:

insert into Table(column1, column2,....)
values (value1, value2,.....)
go
select scope_identity()
go

En este caso, scope_identity() definido dentro en lugar de activador devuelve el valor correcto, pero scope_identity() en la declaración anterior devuelve nulo y la aplicación arroja un error en este punto. Supongo que esto se debe a que la inserción está ocurriendo dentro del disparador que no está dentro del alcance de scope_identity anterior. Sé que este problema se puede resolver al tener un disparador posterior en lugar de un disparador, pero la tabla contiene columnas ntext que me impedirían usar el disparador posterior. Convertir columnas ntext a nvarchar (max) tampoco es una opción para mí. ¿Alguna idea sobre cómo puedo hacer que select scope_identity() devuelva el valor correcto?

Gracias de antemano.

preguntado el 22 de mayo de 12 a las 19:05

Publique el contenido del activador. -

select scope_identity() debe estar en el mismo lote que la inserción; en otras palabras, debe eliminar go. -

@Ben: No puedo publicar el disparador aquí, pero es algo como esto: establezca ansi_nulls en ir, establezca el identificador citado en ir, cree el disparador dbo. .) seleccionar columna1, columna2,... desde insertado seleccionar scope_identity() end -

1 Respuestas

OK, puedo reproducir su problema y tener una explicación y una solución.

use tempdb
go
set ansi_nulls on 
set quoted_identifier on 
go 
create table sampletable (
ix int identity primary key,
column1 nvarchar(50),
column2 nvarchar(50)
)
go
go
      /* First with no trigger - works fine */
insert sampletable(column1, column2)
select 'a', 'b'
select @@identity, scope_identity(), ident_current('sampletable')
select * from sampletable

go
      /* create instead trigger */
create trigger dbo.sampletrigger on sampletable 
instead of insert 
as 
begin 
insert into sampletable(column1, column2) select column1, column2 from inserted 
end
go

      /* Now scope_identity() is null */
insert sampletable(column1, column2)
select 'a', 'b'
select @@identity, scope_identity(), ident_current('sampletable')
select * from sampletable
go
go
go
drop table sampletable

Scope_identity() es nulo porque no insertó una fila con una identidad en el ámbito actual.

Scope_identity() es la última identidad insertada en el ámbito actual en el lote actual. El disparador es un ámbito separado, por lo que fuera del disparador es nulo. necesitas usar @@identity que es la última identidad insertada en el lote, independientemente del alcance.

Usted no pueden utilizado ident_current('sampletable') cuál es la última identidad insertada en cualquier lote y cualquier sesión en esa tabla específica, porque eso potencialmente detectará cambios debido a otros usuarios simultáneos.

contestado el 14 de mayo de 14 a las 18:05

Gracias por la respuesta. Sé que si uso @@identity o ident_current('sampletable') devolverá un valor no nulo. El problema aquí es que las siguientes declaraciones de mi pregunta original son generadas automáticamente por la aplicación y no tengo acceso al código de fondo. Por lo tanto, no puedo cambiar scope_identity() a @@identity o ident_current(''). insertar en la tabla (columna 1, columna 2, ....) valores (valor 1, valor 2, .....) ir a seleccionar scope_identity() ir Básicamente, necesito una solución para que el anterior scope_identity() devuelva un valor no nulo. No estoy seguro si esto es posible. - Anutosh Datta

@AnutoshDatta, necesita encontrar una manera de hacerlo usando un AFTER dispara entonces. Como aún no nos has dicho lo que estás haciendo, no puedo ayudarte más. - paquet

Este activador crea entradas de registro de cambios para la tabla. La razón por la que estoy usando en lugar de desencadenar es que la tabla tiene columnas ntext. No puedo cambiarlo a nvarchar(max) ya que afectará a otras áreas. De todas formas, gracias por su ayuda. - Anutosh Datta

@AnutoshDatta, hay una manera de resolver ese problema, ya que hago exactamente eso. Mira mi respuesta aquí: stackoverflow.com/questions/9101924/… - paquet

@Ben No puedo encontrar ningún lugar en línea que indique que ident_current es específico del lote, parece que solo devuelve la identificación más reciente creada en una tabla determinada. Decir que es un lote específico parece implicar alcance. En la mayoría de los escenarios, probablemente sea razonable suponer que estos son los mismos, pero con suficiente carga: ¿no se garantizaría que la ID más reciente y la ID creada dentro de un script determinado sean las mismas? - fordareh

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.