2009-01-23 16 views
50

Estoy usando este código para restablecer la identidad de una tabla:DBCC CHECKIDENT Establece identidad a 0

DBCC CHECKIDENT('TableName', RESEED, 0) 

Esto funciona bien la mayor parte del tiempo, con la primera inserción Yo inserción 1 en la columna de Id . Sin embargo, si dejo caer el db y lo vuelvo a crear (usando los scripts que he escrito) y luego llamo a DBCC CHECKIDENT, el primer elemento insertado tendrá un ID de 0.

¿Alguna idea?

EDIT: Después de investigar descubrí que no leí la documentación adecuada:. http://msdn.microsoft.com/en-us/library/aa258817(SQL.80).aspx - "El valor de identidad actual se establece en el new_reseed_value Si no hay filas se han insertado a la mesa desde que fue creado, la primera fila insertada después de ejecutar DBCC CHECKIDENT utilizará new_reseed_value como la identidad. de lo contrario, la siguiente fila insertada utilizará new_reseed_value + 1. "

Respuesta

17

Como dijiste en tu pregunta, es documented behavior. Aún así me parece extraño. Utilizo para repoblar la base de datos de prueba y aunque no confío en los valores de los campos de identidad, fue un poco molesto tener diferentes valores al llenar la base de datos por primera vez desde cero y después de eliminar todos los datos y volver a llenarlos.

Una posible solución es utilizar truncar para limpiar la tabla en lugar de eliminar. Pero luego debe eliminar todas las restricciones y volver a crearlas después

De esta forma, siempre se comporta como una tabla recién creada y no hay necesidad de llamar a DBCC CHECKIDENT. El primer valor de identidad será el especificado en la definición de la tabla y será la misma sin importar si inserta los datos por primera vez o para el N-ésimo

+1

ese enlace parece para estar muerto, la documentación actual https://msdn.microsoft.com/en-us/library/ms176057.aspx, dice que es solo el comportamiento esperado para las versiones anteriores a 2012, pero eso no parece ser cierto (pruebas en la versión 2012, la compatibilidad establecida en 2012, sigue teniendo problemas). – jmoreno

5

Cambio declaración a

DBCC CHECKIDENT('TableName', RESEED, 1) 

Esto iniciará a partir de 2 (o 1 cuando n recreas la tabla), pero nunca será 0.

42

Tiene razón en lo que escribe en la edición de su pregunta.

Después de ejecutar DBCC CHECKIDENT('TableName', RESEED, 0):
- mesas de nueva creación se iniciará con la identidad 0
- tablas existentes continuarán con la identidad 1

La solución está en el guión de abajo, que es una especie de mala-mans-truncado :)

-- Remove all records from the Table 
DELETE FROM TableName 

-- Use sys.identity_columns to see if there was a last known identity value 
-- for the Table. If there was one, the Table is not new and needs a reset 
IF EXISTS (SELECT * FROM sys.identity_columns WHERE OBJECT_NAME(OBJECT_ID) = 'TableName' AND last_value IS NOT NULL) 
    DBCC CHECKIDENT (TableName, RESEED, 0); 
+1

Muy bien, pero cuando se trata de varios esquemas es posible que desee ajustar esto un poco para que coincida con 'object_id' en lugar de usar' OBJECT_NAME() 'para buscar el nombre de la tabla:' IF EXISTS (SELECT * FROM sys.identity_columns WHERE object_id = OBJECT_ID ('Schema.TableName') Y last_value IS NOT NULL') – Nick

1

Hice esto como un experimento para restablecer el valor a 0 porque quiero que mi primera columna de identidad sea 0 y esté funcionando.

dbcc CHECKIDENT(MOVIE,RESEED,0) 
dbcc CHECKIDENT(MOVIE,RESEED,-1) 
DBCC CHECKIDENT(MOVIE,NORESEED) 
1
USE AdventureWorks2012; 
GO 
DBCC CHECKIDENT ('Person.AddressType', RESEED, 0); 
GO 



AdventureWorks2012=Your databasename 
Person.AddressType=Your tablename 
1

he utilizado este en SQL para establecer identidad a un valor particular: -

DECLARE @ID int = 42; 
DECLARE @TABLENAME varchar(50) = 'tablename' 

DECLARE @SQL nvarchar(1000) = 'IF EXISTS (SELECT * FROM sys.identity_columns WHERE OBJECT_NAME(OBJECT_ID) = '''[email protected]+''' AND last_value IS NOT NULL) 
    BEGIN 
     DBCC CHECKIDENT('[email protected]+', RESEED,' + CONVERT(VARCHAR(10),@ID-1)+'); 
    END 
    ELSE 
    BEGIN 
     DBCC CHECKIDENT('[email protected]+', RESEED,' + CONVERT(VARCHAR(10),@ID)+'); 
    END'; 
EXEC (@SQL); 

Y esto en C# para ajustar un valor particular: -

SetIdentity(context, "tablename", 42); 
. 
. 
private static void SetIdentity(DbContext context, string table,int id) 
{ 
    string str = "IF EXISTS (SELECT * FROM sys.identity_columns WHERE OBJECT_NAME(OBJECT_ID) = '" + table 
     + "' AND last_value IS NOT NULL)\nBEGIN\n"; 
    str += "DBCC CHECKIDENT('" + table + "', RESEED," + (id - 1).ToString() + ");\n"; 
    str += "END\nELSE\nBEGIN\n"; 
    str += "DBCC CHECKIDENT('" + table + "', RESEED," + (id).ToString() + ");\n"; 
    str += "END\n"; 
    context.Database.ExecuteSqlCommand(str); 
} 

Esto se basa en las respuestas anteriores y siempre se asegura de que el siguiente valor sea 42 (en este caso).

0

Parece ridículo que no pueda establecer/restablecer una columna de identidad con un solo comando para cubrir ambos casos de si la tabla ha tenido registros insertados o no. ¡No podía entender el comportamiento que estaba experimentando hasta que tropecé con la pregunta anterior sobre SO! Mi solución - feo pero funciona - es verificar explícitamente la tabla sys.identity_columns.last_value que le dice si la tabla ha tenido o no registros insertados, y llama al comando DBCC CHECKIDENT apropiado en cada caso: DECLARE @last_value INT = CONVERT(INT, (SELECT last_value FROM sys.identity_columns WHERE OBJECT_NAME(OBJECT_ID) = 'MyTable')); IF @last_value IS NULL BEGIN -- Table newly created and no rows inserted yet; start the IDs off from 1 DBCC CHECKIDENT ('MyTable', RESEED, 1); END ELSE BEGIN -- Table has rows; ensure the IDs continue from the last ID used DECLARE @lastValUsed INT = (SELECT ISNULL(MAX(ID),0) FROM MyTable); DBCC CHECKIDENT ('MyTable', RESEED, @lastValUsed); END

Cuestiones relacionadas