Як я розумію ваше запитання, ви маєте існуючу таблицю зі стовпцем, який до цього часу був заповнений ручними значеннями, і тепер ви хочете (1) зробити цей стовпець IDENTITY
стовпцем, і (2) переконатися, що IDENTITY
початки від останнього значення в існуючих рядках.
Спочатку кілька тестових даних, з якими можна грати:
CREATE TABLE dbo.ident_test (
id int NOT NULL,
xyz varchar(10) NOT NULL,
CONSTRAINT PK_ident_test PRIMARY KEY CLUSTERED (id)
);
INSERT INTO dbo.ident_test (id, xyz)
VALUES (1, 'test'),
(2, 'test'),
(5, 'test'),
(6, 'test'),
(10, 'test'),
(18, 'test'),
(19, 'test'),
(20, 'test');
Мета - зробити стовпчик первинного ключа таблиці id
- IDENTITY
стовпчик, який розпочнеться о 21 для наступного вставленого запису. У цьому прикладі стовпець xyz
представляє всі інші стовпці таблиці.
Перш ніж робити щось, будь ласка, прочитайте попередження внизу цієї публікації.
По-перше, якщо щось піде не так:
BEGIN TRANSACTION;
Тепер додамо тимчасовий робочий стовпець id_temp
і встановимо цей стовпець у значення існуючих id
стовпців:
ALTER TABLE dbo.ident_test ADD id_temp int NULL;
UPDATE dbo.ident_test SET id_temp=id;
Далі нам потрібно скинути існуючий id
стовпець (ви не можете просто "додати" IDENTITY
до існуючого стовпця, ви повинні створити стовпчик як an IDENTITY
). Первинний ключ також повинен пройти, оскільки від нього залежить стовпчик.
ALTER TABLE dbo.ident_test DROP CONSTRAINT PK_ident_test;
ALTER TABLE dbo.ident_test DROP COLUMN id;
... і додайте стовпець знову, на цей раз як IDENTITY
основний ключ, разом із первинним ключем:
ALTER TABLE dbo.ident_test ADD id int IDENTITY(1, 1) NOT NULL;
ALTER TABLE dbo.ident_test ADD CONSTRAINT PK_ident_test PRIMARY KEY CLUSTERED (id);
Ось де це стає цікавим. Ви можете ввімкнути IDENTITY_INSERT
в таблиці, що означає, що ви можете вручну визначити значення IDENTITY
стовпця під час вставлення нових рядків (однак не оновлюючи існуючі рядки).
SET IDENTITY_INSERT dbo.ident_test ON;
З цим набором DELETE
усі рядки таблиці, але рядки, які ви видаляєте, входять OUTPUT
у ту саму таблицю - але з конкретними значеннями для id
стовпця (із стовпця резервного копіювання).
DELETE FROM dbo.ident_test
OUTPUT deleted.id_temp AS id, deleted.xyz
INTO dbo.ident_test (id, xyz);
Після цього, IDENTITY_INSERT
знову вимкніть.
SET IDENTITY_INSERT dbo.ident_test OFF;
Відкиньте тимчасовий стовпець, який ми додали:
ALTER TABLE dbo.ident_test DROP COLUMN id_temp;
І, нарешті, перезавантажте IDENTITY
стовпчик, щоб наступний запис id
відновився після найвищого наявного числа у id
стовпці:
DECLARE @maxid int;
SELECT @maxid=MAX(id) FROM dbo.ident_test;
DBCC CHECKIDENT ("dbo.ident_test", RESEED, @maxid)
Перевіряючи приклад таблиці, найбільше id
число - 20.
SELECT * FROM dbo.ident_test;
Додайте ще один рядок і перевірте його новий IDENTITY
:
INSERT INTO dbo.ident_test (xyz) VALUES ('New row');
SELECT * FROM dbo.ident_test;
У прикладі буде новий рядок id=21
. Нарешті, якщо ви щасливі, виконайте транзакцію:
COMMIT TRANSACTION;
Важливо
Це не тривіальна операція, і вона несе в собі досить багато ризиків, про які вам слід знати.
Робіть це у спеціалізованому тестовому середовищі. Майте резервні копії. :)
Мені подобається використовувати, BEGIN/COMMIT TRANSACTION
тому що це заважає іншим процесам не возитися з таблицею, поки ви в середині їх змінюєте, і це дає вам можливість повернути все назад, якщо щось піде не так. Однак будь-який інший процес, який намагається отримати доступ до вашої таблиці, перш ніж здійснити транзакцію, закінчиться в очікуванні. Це може бути дуже погано, якщо у вас великий стіл та / або ви перебуваєте у виробничому середовищі.
OUTPUT .. INTO
не працюватиме, якщо ваша цільова таблиця має обмеження щодо зовнішніх ключів або будь-яку з інших функцій, яких я не можу запам'ятати вгорі голови. Ви можете замість цього вивантажити дані у тимчасову таблицю, а потім вставити їх у вихідну таблицю. Можливо, ви зможете використовувати комутацію розділів (навіть якщо ви не використовуєте розділи).
Запускайте ці оператори по черзі, а не як пакетне чи у збереженій процедурі.
Спробуйте придумати інші речі, які можуть залежати від id
стовпчика, який ви опускаєте та створюєте заново. Будь-які індекси доведеться скинути та відтворити заново (як ми це робили з первинним ключем). Не забудьте написати сценарій кожного індексу та обмежень, які вам потрібно буде відтворити заздалегідь.
Вимкніть будь-які INSERT
та DELETE
тригери на столі.
Якщо повторне створення таблиці - це варіант:
Якщо повторне створення таблиці - це варіант для вас, все набагато простіше:
- Створення порожній таблиці з
id
стовпчика у вигляді IDENTITY
,
- Набір
IDENTITY_INSERT ON
для столу,
- Населяйте таблицю,
- Встановити
IDENTITY_INSERT OFF
і
- Перевчила особу.
IDENTITY
?