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. "

497   8  

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

    Ничего не найдено.