CHECKIDENT DBCC устанавливает идентификатор 0
Я использую этот код для reset идентификатора в таблице:
DBCC CHECKIDENT('TableName', RESEED, 0)
Это работает отлично в большинстве случаев, с первой вставкой, которую я вставляю 1 в столбец идентификатора. Однако, если я удаляю db и воссоздаю его (используя написанные скрипты), а затем вызываю 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."
Ответы
Ответ 1
Как вы указали в своем вопросе, это документированное поведение. Мне все еще кажется странным. Я использую, чтобы повторно заполнить тестовую базу данных, и хотя я не полагаюсь на значения полей идентификации, было немного раздражающе иметь разные значения при первом заполнении базы данных с нуля и после удаления всех данных и повторного заполнения.
Возможным решением является использование truncate для очистки таблицы вместо удаления. Но тогда вам нужно отбросить все ограничения и потом их воссоздать
Таким образом, он всегда ведет себя как вновь созданная таблица, и нет необходимости вызывать DBCC CHECKIDENT. Первое значение идентификатора будет указано в определении таблицы, и оно будет одинаковым независимо от того, вставляете ли вы данные в первый раз или для N-го
Ответ 2
Вы правы в том, что вы пишете при редактировании вашего вопроса.
После запуска DBCC CHECKIDENT('TableName', RESEED, 0)
:
- Новые созданные таблицы начнутся с идентификатора 0
- Существующие таблицы будут продолжаться с идентификатором 1
Решение находится в script ниже, это своего рода бедный mans-truncate:)
-- 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);
Ответ 3
Измените оператор на
DBCC CHECKIDENT('TableName', RESEED, 1)
Это начнется с 2 (или 1 при воссоздании таблицы), но никогда не будет 0.
Ответ 4
Я сделал это как эксперимент с reset значением 0, так как я хочу, чтобы мой первый столбец идентичности был 0 и он работал.
dbcc CHECKIDENT(MOVIE,RESEED,0)
dbcc CHECKIDENT(MOVIE,RESEED,-1)
DBCC CHECKIDENT(MOVIE,NORESEED)
Ответ 5
Кажется смешным, что вы не можете установить/сбросить столбец идентификаторов с помощью одной команды, чтобы охватить оба случая, если в таблицу были вставлены записи. Я не мог понять поведение, которое я испытывал, пока я не наткнулся на этот вопрос на SO!
Мое решение (некрасиво, но работает) состоит в том, чтобы явно проверить таблицу sys.identity_columns.last_value
(которая сообщает вам, вставлены ли в таблицу записи) и вызывать соответствующую команду DBCC CHECKIDENT
в каждом случае. Это выглядит следующим образом:
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
Ответ 6
См. также здесь: http://sqlblog.com/blogs/alexander_kuznetsov/archive/2008/06/26/fun-with-dbcc-chekident.aspx
Это документированное поведение, почему вы запускаете CHECKIDENT, если вы воссоздаете таблицу, в этом случае пропустите шаг или используйте TRUNCATE (если у вас нет отношений FK)
Ответ 7
Я использовал это в SQL для установки IDENTITY для определенного значения: -
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);
И это в С# для установки определенного значения: -
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 (в данном случае).
Ответ 8
Просто сделайте это:
IF EXISTS (SELECT * FROM tablename)
BEGIN
DELETE from tablename
DBCC checkident ('tablename', reseed, 0)
END
Ответ 9
USE AdventureWorks2012;
GO
DBCC CHECKIDENT ('Person.AddressType', RESEED, 0);
GO
AdventureWorks2012=Your databasename
Person.AddressType=Your tablename