Cómo obtener el siguiente valor de identidad de SQL Server


Necesito obtener el siguiente valor de identidad de SQL Server.

Utilizo este código :

SELECT IDENT_CURRENT('table_name') + 1

Esto es correcto, pero cuando el table_name está vacío (y el siguiente valor de identidad es "1") devuelve " 2 " pero el resultado es "1"

Author: gotqn, 2013-12-27

5 answers

Creo que querrá buscar una forma alternativa de calcular el siguiente valor disponible (como establecer la columna en auto-increment).

De la documentación IDENT_CURRENT, con respecto a las tablas vacías:

Cuando el valor IDENT_CURRENT es NULL (porque la tabla nunca ha contenido filas o ha sido truncada), la función IDENT_CURRENT devuelve el valor seed.

Ni siquiera parece tan confiable, especialmente si terminas diseñar una aplicación que tenga más de una persona escribiendo a la mesa al mismo tiempo.

Tenga cuidado al usar IDENT_CURRENT para predecir el próximo valor de identidad generado. El valor generado real puede ser diferente de IDENT_CURRENT más IDENT_INCR debido a inserciones realizadas por otras sesiones.

 11
Author: Grant Winney,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:32:03

Tiendo a estar de acuerdo con otros carteles en que esta no es la manera correcta de hacer esto, sin embargo, puede ser conveniente para ciertos casos. Varias publicaciones preguntan por qué hacer esto, y permítanme darles un ejemplo donde fue conveniente para mí, y cómo y por qué.

Estoy implementando un nodo Bitcoin. Quiero el blockchain almacenado en una base de datos SQL. Cada bloque se recibe de la red de otros nodos y mineros. Los detalles se pueden encontrar en otra parte.

Cuando recibe un bloque que contiene un encabezado, cualquier número de transacciones y cada transacción cualquier número de entradas y salidas. Tengo 4 tablas en mi base de datos - lo has adivinado - una tabla de encabezado, tabla de transacciones, tabla de entradas y tabla de salidas. Cada fila de la tabla transaction, inputs y outputs está vinculada con IDs entre sí en la fila de encabezado.

Algunos bloques contienen varios miles de transacciones. Algunas transacciones cientos de entradas y / o salidas. Los necesito almacenados en la base de datos de una llamada conveniente en C# sin comprometer la integridad (todos los IDS se enlazan) y con un rendimiento decente, que no puedo obtener confirmando fila por fila cuando hay cerca de 10000 confirmaciones.

En su lugar, me aseguro de sincronizar-bloquear mi objeto de base de datos en C# durante la operación (y no tengo que preocuparme de que otros procesos accedan a la base de datos también), por lo que puedo hacer convenientemente un IDENT_CURRENT en las 4 tablas, devolver los valores de un proc almacenado, llenar las casi 10000 filas en 4 List mientras incrementa los IDs y llama al SqlBulkCopy.Método WriteToServer con opción SqlBulkCopyOptions.KeepIdentity set, y luego enviarlo todo en 4 llamadas simples, una para cada mesa.

La ganancia de rendimiento (en un portátil de rango medio de 4-5 años) iba de unos 60-90 segundos a 2-3 segundos para los bloques realmente grandes, así que me alegré de aprender sobre IDENT_CURRENT().

La solución podría no ser elegante, podría no ser por el libro por así decirlo, pero es conveniente y simple. También hay otras formas de lograr esto, lo sé, pero esto fue sencillo y tomó unas horas para implementarlo. Solo asegúrese de que no tiene problemas de concurrencia.

 5
Author: Søren L. Fog,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-13 15:44:25

En caso de que su tabla esté vacía, esta consulta funcionará perfectamente.

SELECT
  CASE
    WHEN (SELECT
        COUNT(1)
      FROM tablename) = 0 THEN 1
    ELSE IDENT_CURRENT('tablename') + 1
  END AS Current_Identity;
 5
Author: Abhijit Gosavi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-27 16:43:45

Sé que ya hay una respuesta, pero realmente me molesta que todas mis búsquedas a lo largo de las líneas de "get next identity sql server" vinieron con soluciones escamosas (como simplemente seleccionar el valor de identidad actual y agregar 1) o "no se puede hacer de manera confiable".

Hay un par de maneras de hacer esto.

SQL Server > = 2012

CREATE SEQUENCE dbo.seq_FooId START WITH 1 INCREMENT BY 1
GO

CREATE TABLE dbo.Foos (
    FooId int NOT NULL 
        DEFAULT (NEXT VALUE FOR dbo.seq_FooId)
        PRIMARY KEY CLUSTERED 
)
GO

// Get the next identity before an insert
DECLARE @next_id = NEXT VALUE FOR dbo.seq_FooId

SQL Server 2012 introdujo el objeto SEQUENCE. En este caso, la secuencia se incrementará cada vez que se llame a NEXT VALUE FOR, por lo que no necesita preocuparse por la concurrencia.

SQL Server
CREATE TABLE dbo.Foos (
    FooId int NOT NULL 
        IDENTITY (1, 1)
        PRIMARY KEY CLUSTERED 
)
GO

// Get the next identity before an insert
BEGIN TRANSACTION
SELECT TOP 1 1 FROM dbo.Foos WITH (TABLOCKX, HOLDLOCK)
DECLARE @next_id int = IDENT_CURRENT('dbo.Foos') + IDENT_INCR('dbo.Foos');
DBCC CHECKIDENT('dbo.Foos', RESEED, @next_id)
COMMIT TRANSACTION

Probablemente querrá encapsular todo eso en un procedimiento almacenado, especialmente porque la instrucción DBCC requiere acceso elevado y probablemente no querrá que todos tengan ese tipo de acceso.

No es tan elegante como NEXT VALUE FOR, pero debería ser confiable. Tenga en cuenta que obtendrá 2 para su primer valor si no hay filas en la tabla, pero si tiene la intención de usar siempre esto método para obtener la siguiente identidad, puede sembrar la identidad en 0 en lugar de 1 (con IDENTITY (0, 1)) si está decidido a comenzar con 1.

¿por Qué alguien querría hacer esto?

No puedo hablar por el póster de la pregunta, pero el libro 'Domain Driven Design' y la muestra 'oficial' de DDD usa esta técnica (o al menos lo insinúa) como una forma de imponer que las entidades siempre tengan un identificador válido. Si su entidad tiene un identificador falso (como -1 o default(int) o null) hasta que sea INSERT ed en la base de datos, está potencialmente filtrando una preocupación de persistencia.

 2
Author: tuespetre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-05 18:08:20
SELECT isnull(IDENT_CURRENT('emp') + IDENT_INCR('emp'),1)
 2
Author: Islam Gx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-23 15:34:41