DBCC CHECKIDENT встановлює ідентичність на 0


75

Я використовую цей код для скидання ідентифікації в таблиці:

DBCC CHECKIDENT('TableName', RESEED, 0)

Це працює нормально більшу частину часу, при першій вставці я вставляю 1 у стовпець Id. Однак, якщо я скину БД і відтвору її (за допомогою написаних мною сценаріїв), а потім викликаю DBCC CHECKIDENT, перший вставлений елемент матиме ідентифікатор 0.

Будь-які ідеї?

РЕДАГУВАТИ: Після дослідження я виявив, що не прочитав документацію належним чином - "Поточне значення ідентифікатора має значення new_reseed_value. Якщо до таблиці з моменту її створення не було вставлено рядків, перший рядок, вставлений після виконання DBCC CHECKIDENT, використовуйте new_reseed_value як ідентичність. В іншому випадку наступний вставлений рядок використовуватиме new_reseed_value + 1. "

Відповіді:


26

Як ви зазначили у своєму питанні, це документована поведінка . Я все ще вважаю це дивним, хоча. Я використовую для повторного заповнення тестової бази даних, і хоча я не покладаюсь на значення полів ідентифікації, було трохи прикро мати різні значення при першому заповненні бази даних з нуля та після видалення всіх даних та повторного заповнення.

Можливим рішенням є використання truncate для очищення таблиці замість видалення. Але тоді потрібно скинути всі обмеження і відтворити їх згодом

Таким чином, він завжди поводиться як новостворена таблиця, і немає необхідності викликати DBCC CHECKIDENT. Першим значенням ідентичності буде вказане у визначенні таблиці, і воно буде однаковим, незалежно від того, вставляєте ви дані вперше або для N-го


2
це посилання здається мертвим, в поточній документації msdn.microsoft.com/en-us/library/ms176057.aspx сказано, що очікувана поведінка лише для версій до 2012 року, але це, схоже, не відповідає дійсності (тестування на Версія 2012, сумісність встановлена ​​на 2012, проблема все ще спостерігається).
jmoreno

67

Ви маєте рацію в тому, що пишете в редакції свого запитання.

Після запуску 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);

2
Дуже добре, але, маючи справу з кількома схемами, можливо, ви захочете трохи підправити це, щоб відповідати, object_idа не використовувати OBJECT_NAME()для пошуку назви таблиці IF EXISTS (SELECT * FROM sys.identity_columns WHERE object_id = OBJECT_ID('Schema.TableName') AND last_value IS NOT NULL
Нік,

5

Змінити заяву на

  DBCC CHECKIDENT('TableName', RESEED, 1)

Це почнеться з 2 (або 1 при відтворенні таблиці), але ніколи не буде 0.


3

Я зробив це як експеримент, щоб скинути значення до 0, оскільки я хочу, щоб мій перший стовпець ідентичності був 0, і він працює.

dbcc CHECKIDENT(MOVIE,RESEED,0)
dbcc CHECKIDENT(MOVIE,RESEED,-1)
DBCC CHECKIDENT(MOVIE,NORESEED)

3

Виглядає смішним, що ви не можете встановити / скинути стовпець ідентичності за допомогою однієї команди, щоб охопити обидва випадки того, чи були в таблиці вставлені записи чи ні. Я не міг зрозуміти поведінку, яку відчував, поки не наткнувся на це питання на 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


1

Я використовував це в 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) = '''+@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 (у цьому випадку).


1

Позичення з відповіді Зіфракса ...

USE DatabaseName

DECLARE @ReseedBit BIT = 
    COALESCE((SELECT SUM(CONVERT(BIGINT, ic.last_value))
                FROM sys.identity_columns ic
                INNER JOIN sys.tables t ON ic.object_id = t.object_id), 0)
DECLARE @Reseed INT = 
CASE 
    WHEN @ReseedBit = 0 THEN 1 
    WHEN @ReseedBit = 1 THEN 0 
END

DBCC CHECKIDENT ('dbo.table_name', RESEED, @Reseed);

Застереження: Це призначено для використання в ситуаціях сукупності посилальних даних, коли БД ініціалізується таблицями визначення типу перерахування, де значення ІД у цих таблицях завжди повинні починатися з 1. Перший раз, коли БД створюється (наприклад, під час SSDT- Публікація БД) @Reseed має бути рівним 0, але при скиданні даних, тобто видаленні даних та їх повторній вставці, @Reseed має бути 1. Отже, цей код призначений для використання в збереженій процедурі скидання даних БД, яка може викликається вручну, але також викликається із сценарію після розгортання у проекті SSDT-DB. Таким чином, вставки довідкових даних визначаються лише в одному місці, але не обмежуються використанням лише після розгортання під час публікації, вони також доступні для подальшого використання (для підтримки розробника та автоматизованого тестування тощо).


Є простіший спосіб зробити те саме, пробачте моє форматування. ДЕКЛАРУЙТЕ @Reseed INT = (ВИБЕРІТЬ ТОП 1 СПРАВУ, КОЛИ КОНВЕРТУЮТЬ (BIGINT, ic.last_value)> 0, ПОТІМ 0 ІНШЕ 1 КІНЦЕ, як повторно з FROM sys.identity_columns ic ВНУТРІШНЄ ПРИЄДНАННЯ sys.tables t ON ic.object_id = t.object_id і t. object_id = OBJECT_ID (@tableName))
Nikhil Doomra

0

Просто зробіть це:

IF EXISTS (SELECT * FROM tablename)
BEGIN
    DELETE from  tablename
    DBCC checkident ('tablename', reseed, 0)
END

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.