2009-10-09 22 views
7

¿Es posible en SQL (SQL Server) recuperar el siguiente ID (entero) de una columna de identidad en una tabla antes y sin insertar una fila? Este no es necesariamente el ID más alto más 1 si se eliminó la fila más reciente.Obteniendo el siguiente ID sin insertar una fila

Lo pregunto porque ocasionalmente tenemos que actualizar una base de datos en vivo con filas nuevas. El ID de la fila se usa en nuestro código (por ejemplo, Switch (ID) {Case ID:} y debe ser el mismo. Si nuestro DB de desarrollo y DB vivo no están sincronizados, sería bueno predecir una ID de fila por adelantado antes del despliegue.

que pude por supuesto conjunto de identidad OFF SET INSERT_IDENTITY ON o ejecutar una transacción (no esta tirada hacia atrás el ID?), etc, pero se preguntaban si había una función que ha devuelto el siguiente ID (sin incrementarlo) .

+0

Una transacción no revertirá el contador de identidades y siempre existe el riesgo de que otro subproceso use el número que cree que obtendrá más adelante. – idstam

+0

Gracias por este @idstam sospeché esto. – iWeasel

Respuesta

8

Editar:

Después de pasar un número de horas que comparan los vertederos de página entera, me di cuenta de que hay una manera más fácil y que debería de mantenido al DMV.

El valor sobrevive a una copia de seguridad/restauración, lo cual es una clara indicación de que está almacenado - Volqué todas las páginas en la base de datos y no pude encontrar la ubicación/alteración cuando se agregó un registro. Comparar 200,000 descargas de páginas en línea no es divertido.

Había utilizado la consola de administración dedicada. Tomé un volcado de cada una de las tablas internas expuestas insertadas en una fila y luego volví a tirar las tablas del sistema. Ambos volcados fueron idénticos, lo que indica que, aunque sobrevivió y, por lo tanto, debe almacenarse, no está expuesto ni siquiera en ese nivel.

Así que después de girar en círculo, me di cuenta de que el DMV sí tenía la respuesta.

create table foo (MyID int identity not null, MyField char(10)) 
insert into foo values ('test') 
go 10 

-- Inserted 10 rows 
select Convert(varchar(8),increment_value) as IncrementValue, 
    Convert(varchar(8),last_value) as LastValue 
from sys.identity_columns where name ='myid' 


-- insert another row 
insert into foo values ('test') 

-- check the values again 
select Convert(varchar(8),increment_value) as IncrementValue, 
    Convert(varchar(8),last_value) as LastValue 
from sys.identity_columns where name ='myid' 

-- delete the rows 
delete from foo 


-- check the DMV again 
select Convert(varchar(8),increment_value) as IncrementValue, 
    Convert(varchar(8),last_value) as LastValue 
from sys.identity_columns where name ='myid' 

-- value is currently 11 and increment is 1, so the next insert gets 12 
insert into foo values ('test') 
select * from foo 

Result: 
MyID  MyField 
----------- ---------- 
12   test  

(1 row(s) affected) 

El hecho de que las filas consiguieron removidos, el último valor fue sin restablecerse, por lo que el último valor + Valor mínimo debería ser la respuesta correcta.

También voy a escribir el episodio en mi blog.

Ah, y el atajo para todo:

select ident_current('foo') + ident_incr('foo') 

lo que en realidad resulta ser fácil - pero todo esto asume que nadie más ha utilizado su identificación mientras lo tienes de vuelta. Está bien para la investigación, pero no me gustaría usarlo en el código.

+0

¡Yikes! +1 por una respuesta que me hizo sonreír – iWeasel

+0

He pasado la mayor parte de la noche investigando, pensando que sería un artículo decente para el blog, y lo descubrí. Editando mi respuesta. – Andrew

+0

@Andrew. La idea de que tienes demasiado tiempo en tus manos se me ocurrió. Por otro lado, muchas gracias. Gran respuesta. – iWeasel

2

en lugar de utilizar una columna IDENTITY, se puede usar una columna UNIQUEIDENTIFIER (GUID) como el identificador único de la fila e insertar valores conocidos.

la otra opción (que uso) es S ET IDENTITY_INSERT ON, donde los ID de fila se gestionan en un solo 'documento' controlado por fuente.

+1

Excelente punto, pero los Guids no son realmente prácticos en esta tabla en particular y tienen un poco de espacio con hambre. Yo uso IDENTITY_INSERT en este momento. Funciona, pero se preguntan si hay una alternativa. :) – iWeasel

+0

+1 para las guías. Las guías tienen una penalización de rendimiento relativa a una columna de autoincremento (aunque el espacio adicional que requieren en una fila es trivial), pero eliminan por completo la necesidad de saltar por aros como este. – MusiGenesis

+0

La multa es si utiliza el GUID como su clave agrupada, entonces paga un alto precio tanto en términos de rendimiento como de espacio. – Andrew

2

Se puede determinar con bastante facilidad que el último valor utilizado es:

SELECT 
    last_value 
FROM 
    sys.identity_columns 
WHERE 
    object_id = OBJECT_ID('yourtablename') 

Por lo general, el siguiente ID habrá last_value + 1 - pero no hay garantía para eso.

Marc

+1

Precisamente; no hay garantía, por lo que me pregunté si habría una alternativa. :) – iWeasel

+0

No, no hay otra manera - SQL Server solo emitirá realmente la ID cuando realmente hace el INSERT - no hay forma de fingir que :-( –

2

Esto es un poco extraño, pero funciona:

Si quieres saber el valor siguiente, empezar por conseguir el mayor valor más uno:

SELECT max(id) FROM yourtable 

Para hacer que esto funcione, tendrá que restablecer la identidad en la inserción:

DECLARE @value INTEGER 

SELECT @value = max(id) + 1 FROM yourtable 

DBCC CHECKIDENT (yourtable, reseed, @value) 

INSERT INTO yourtable ... 

No exactamente una solución elegante, pero todavía no he tomado mi café ;-)

(Esto también asume que su proceso o cualquier otro proceso entre el primer y el segundo bloque de código no hace nada).

+0

Esto puede no ser elegante, pero lo marcaré como la respuesta para tablas en las que puede estar bastante seguro de que no hay una nueva fila insertada antes de ejecutar esto. – iWeasel

+0

Lo siento, Jeff, @Andrew pasó toda la noche en una edición excelente. Es una delicia. Tendrá que volver a asignar la respuesta – iWeasel

7

tratar IDENT_CURRENT:

Select IDENT_CURRENT('yourtablename') 

Esto funciona incluso si no se ha insertado ninguna fila en la sesión actual:

devuelve el último valor de identidad generado para una tabla o vista especificada . El último valor de identidad generado puede ser para cualquier sesión y cualquier ámbito.

+1

Agradable.Esto obtiene el valor más reciente utilizado, y la página MSDN alerta que "Tenga cuidado al usar IDENT_CURRENT para predecir el siguiente valor de identidad generado. El valor generado real puede ser diferente de IDENT_CURRENT más IDENTITY_SEED debido a inserciones realizadas por otras sesiones". – PaulG

Cuestiones relacionadas