DBCC CHECKIDENT устанавливает идентификатор в 0
Я использую этот код для сброса идентификатора в таблице:
DBCC CHECKIDENT('TableName', RESEED, 0)
это прекрасно работает большую часть времени, с первой вставкой я вставляю 1 в столбец Id. Однако если я отброшу БД и воссоздам ее (используя сценарии, которые я написал), а затем вызову DBCC CHECKIDENT, первый вставленный элемент будет иметь идентификатор 0.
какие идеи?
EDIT: после исследования я узнал, что я не читал документацию правильно:
http://msdn.microsoft.com/en-us/library/aa258817 (SQL.80).aspx - "текущее значение идентификатора устанавливается в значение new_reseed_value. Если строки не были вставлены в таблицу с момента ее создания, первая строка, вставленная после выполнения DBCC CHECKIDENT будет использовать new_reseed_value в качестве идентификатора. В противном случае следующая вставленная строка будет использовать new_reseed_value + 1. "
8 ответов:
Как вы указали в своем вопросе это документированное поведение. Хотя я все еще нахожу это странным. Я использую для повторного заполнения тестовой базы данных, и хотя я не полагаюсь на значения полей идентификаторов, было немного раздражающе иметь разные значения при заполнении базы данных в первый раз с нуля и после удаления всех данных и повторного заполнения.
возможным решением является использование усечь чтобы очистить таблицу вместо удаления. Но затем вам нужно отбросить все ограничения и воссоздать их впоследствии
таким образом, он всегда ведет себя как вновь созданная таблица, и нет необходимости вызывать DBCC CHECKIDENT. Первое значение идентификатора будет указано в определении таблицы, и оно будет одинаковым независимо от того, вставляете ли Вы данные в первый раз или для N-го
Вы правы в том, что вы пишете в редактирование вашего вопроса.
после
DBCC CHECKIDENT('TableName', RESEED, 0):
- Вновь созданные таблицы будут начинаться с идентификатора 0
- Существующие таблицы будут продолжаться с идентификатором 1решение находится в скрипте ниже, это своего рода бедный человек-усечение :)
-- 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);
изменить оператор на
DBCC CHECKIDENT('TableName', RESEED, 1)это будет начинаться с 2 (или 1 при повторном создании таблицы), но это никогда не будет 0.
Смотрите также здесь: http://sqlblog.com/blogs/alexander_kuznetsov/archive/2008/06/26/fun-with-dbcc-chekident.aspx
Это документированное поведение, почему вы запускаете CHECKIDENT, если вы воссоздаете таблицу, в этом случае пропустите шаг или используйте усечение (если у вас нет отношений FK)
Я сделал это в качестве эксперимента, чтобы сбросить значение до 0, поскольку я хочу, чтобы мой первый столбец идентификаторов был 0, и он работает.
dbcc CHECKIDENT(MOVIE,RESEED,0) dbcc CHECKIDENT(MOVIE,RESEED,-1) DBCC CHECKIDENT(MOVIE,NORESEED)
я использовал это в SQL, чтобы установить идентификатор в определенное значение: -
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) = '''+@TABLENAME+''' AND last_value IS NOT NULL) BEGIN DBCC CHECKIDENT('+@TABLENAME+', RESEED,' + CONVERT(VARCHAR(10),@ID-1)+'); END ELSE BEGIN DBCC CHECKIDENT('+@TABLENAME+', RESEED,' + CONVERT(VARCHAR(10),@ID)+'); END'; EXEC (@SQL);и это в C#, чтобы установить определенное значение: -
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); }это основывается на приведенных выше ответах и всегда гарантирует, что следующее значение равно 42 (в данном случае).
кажется смешным, что вы не можете установить/сбросить столбец идентификаторов с помощью одной команды, чтобы покрыть оба случая того, были ли вставлены записи в таблицу. Я не мог понять поведение, которое я испытывал, пока не наткнулся на этот вопрос на SO!
мое решение (некрасиво, но работает), чтобы явно проверить
sys.identity_columns.last_valueтаблица (которая говорит вам, были ли вставлены записи в таблицу) и вызовите соответствующий в каждом случае. Это как следует: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
USE AdventureWorks2012; GO DBCC CHECKIDENT ('Person.AddressType', RESEED, 0); GO AdventureWorks2012=Your databasename Person.AddressType=Your tablename
Comments