post icon

SCOPE_IDENTITY vs IDENT_CURRENT vs @@IDENTITY en SQL Server

En SQL Server al crear tablas podemos determinar que una columna que almacene un tipo de dato entero tenga valores autoincrementales, lo que se conoce como valores de identidad o identity. La cantidad de saltos entre estos valores y el valor inicial pueden ser definidos. Esto quiere decir que si en una tabla definimos varias columnas y una representa la Primary Key a la que se le asigne el valor de identidad, éste irá aumentando automáticamente su valor de acuerdo vayamos agregando registros a la tabla.

Es conveniente tener en cuenta que un valor identity nunca se revierte, es decir, si una transacción produce alguna excepción y realiza el rollback de la misma, ésta dejará un hueco entre los valores del identity.

En algún punto de nuestro sistema necesitaremos recuperar los valores que van generando los identity en nuestras tablas y tenemos 3 maneras correctas de recuperarlos pero se deben saber utilizar cada uno de éstos métodos en el contexto correcto. También existe una cuarta manera no recomendada bajo ningún caso pero muy utilizada por muchos, la misma consiste en hacer una consulta a la tabla recuperando el valor máximo de la misma, así:

SELECT MAX(PK) FROM TABLA;

Esta técnica da la impresión que funciona, de hecho en muchos momentos lo hará correctamente, el problema viene cuando tenemos concurrencia en la BD, teniendo 2 o más transacciones que insertan registros en la tabla. Supongamos: Usuario 1 inserta 1 registro en la tabla A, luego realiza la lectura del valor máximo pero en el momento intermedio entre la inserción y la lectura el usuario 2 inserta otro registro, ocacionando que el usuario 1 obtenga el valor máximo generado por el usuario 2, provocando la obtención incorrecta de valores, por ello debemos evitar esta práctica.

Ahora es donde entra en juego las primeras 3 técnicas que mencionaba anteriormente y en el título del artículo, esas 3 funciones son muy parecidas en funcionamiento ya que todas recuperan valores de identidad pero se diferencian en el contexto que lo hacen. Veamos cual es el objetivo de cada una de ellas y podrán determinar luego cual es la que necesitan.

IDENT_CURRENT

No está limitado a una sesión o ámbito, puede obtener el valor de identidad de una tabla especifica sin importar el momento en que se lo invoque. Requiere explicitamente que indiquemos de cual tabla necesitamos obtener su valor. Ejemplo:

SELECT IDENT_CURRENT ('tabla');

SCOPE_IDENTITY

Devuelve el último valor de identidad insertado en una tabla en la sesión actual dentro de ámbito actual. Supongamos que tenemos 2 tablas T1 y T2 y ambas tienen columnas con valores de identidad. Además teniendo 1 trigger en T1 disparando una inserción en T2. Éste contexto genera 2 ámbitos, la primera el identity de la inserción en T1 y la segunda el identity generado por la inserción hecha mediante el trigger en T2. SCOPE_IDENTITY estará limitado al primer ámbito por lo tanto devolverá el valor generado en la tabla T1.

SELECT SCOPE_IDENTITY();

@@IDENTITY

Devuelve el último valor de identidad insertado en una tabla en la sesión actual diferenciandose del anterior que no está limitado a un ámbito especifico. Continuando con el ejemplo anteriormente explicado, hemos dicho que @@IDENTITY no se limita al ámbito, por lo tanto recuperará el último valor insertado en cualquier ámbito, siendo la inserción generada por el trigger el último ámbito generado, entonces recuperará los valores insertados en T2.

SELECT @@IDENTITY;

Comentarios desde Facebook:

  1. avatar
    Miguel Salazar PERU Google Chrome Windows
    9 julio 2012 at 07:11 #

    Hola que tal , interesante tu explicación ; ahora te pongo un caso tengo una tabla Cabecera (idCabecera,ncampos…) y tengo una tabla detalle (idCabecera,idDetalle,ncampos…) que están relacionadas … si uso SCOPE_IDENTITY() genial me funciona en la cabecera y el valor que obtengo lo envío en el detalle ; pero como hacer con el idDetalle de la tabla detalle sabiendo que en cualquier momento puedo abrir nuevamente la tabla para insertar nuevos registros con ese idCabecera…. uso la función Max ???

    No sé si fui claro en el problema.

    Espero tu respuesta , muchas gracias

    • avatar
      GeekZero PARAGUAY Google Chrome Windows
      9 julio 2012 at 07:27 #

      La función MAX() sólo te traería problemas de concurrencia si fuera el único campo como PK, pero por lo que veo tienes una PK compuesta. Lo que significa que por más que tengas una altísima concurrencia siempre el idCabecera será utilizado por un único cliente, entonces no es problema que él obtenga un el iddetalle con el MAX..

  2. avatar
    Percy Herrera PERU Internet Explorer Windows
    28 enero 2011 at 15:38 #

    Hola, buena literatura a tener en cuenta cuando se desea recuperar el ultimo valor ingresado, pero aqui tengo una pregunta, segun tu experiencia, cual de los 3 casos expuestos seria el que recomendarias y cual es que haz visto que se utiliza mas en proyectos.

    saludos

    Pery Herrera

    • avatar
      GeekZero PARAGUAY Google Chrome Windows
      28 enero 2011 at 16:04 #

      Hola Percy, ninguno es es mejor que otro, sino más bien cada uno se debe usar para un caso o contexto distinto. Si lo utilizas mal podrías tener problemas con tus datos.

      Con respecto a cuales son los más populares suelen ser el SCOPE_IDENTITY() y @@Identity pero no te bases en su popularidad para utilizarlo, sino más bien como ya te decía, según lo que necesites hacer..

Responder