Насколько я понимаю ваш вопрос, у вас есть существующая таблица со столбцом, который до сих пор заполнялся ручными значениями, и теперь вы хотите (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
существующий столбец, вы должны создать столбец как 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
?