Я создал таблицу в БД, которая уже существует в другой БД. Первоначально он был заполнен старыми данными БД. ПК таблицы должен получать значения, которые уже существуют в этих записях, поэтому он не может быть автоинкрементным.
Теперь мне нужно, чтобы новая таблица имела свой PK в качестве автоинкремента. Но как я могу это сделать после того, как ПК уже существует и у него есть данные?
IDENTITY
?Ответы:
Насколько я понимаю ваш вопрос, у вас есть существующая таблица со столбцом, который до сих пор заполнялся ручными значениями, и теперь вы хотите (1) сделать этот столбец
IDENTITY
столбцом и (2) убедиться, чтоIDENTITY
запуски от самого последнего значения в существующих строках.Прежде всего, некоторые тестовые данные для игры:
Цель состоит в том, чтобы создать столбец первичного ключа таблицы, столбец
id
,IDENTITY
который будет начинаться с 21 для следующей вставленной записи. В этом примере столбецxyz
представляет все остальные столбцы таблицы.Прежде чем что-то делать, прочитайте предупреждения внизу этого поста.
Во-первых, на случай, если что-то пойдет не так:
Теперь давайте добавим временную рабочую колонку,
id_temp
и установите для этогоid
столбца значения существующих столбцов:Далее нам нужно удалить существующий
id
столбец (вы не можете просто «добавить»IDENTITY
существующий столбец, вы должны создать столбец какIDENTITY
). Первичный ключ также должен идти, потому что столбец зависит от него.... и снова добавьте столбец, на этот раз как
IDENTITY
, вместе с первичным ключом:Вот где это становится интересным. Вы можете включить
IDENTITY_INSERT
для таблицы, что означает, что вы можете вручную определить значенияIDENTITY
столбца при вставке новых строк (однако, не обновляя существующие строки).С этим набором
DELETE
все строки в таблице, но строки, которые вы удаляете, находятсяOUTPUT
прямо в той же самой таблице - но с определенными значениями дляid
столбца (из резервного столбца).После этого
IDENTITY_INSERT
выключите снова.Удалите временный столбец, который мы добавили:
И, наконец, повторно заполните
IDENTITY
столбец, чтобы следующая записьid
возобновилась после наибольшего существующего числа вid
столбце:Проверяя таблицу примеров, наибольшее
id
число составляет 20.Добавьте еще один ряд и проверьте его новый
IDENTITY
:В примере новая строка будет иметь
id=21
. Наконец, если вы счастливы, совершите транзакцию:Важный
Это не тривиальная операция, и она несет в себе довольно много рисков, о которых вам следует знать.
Сделайте это в специальной тестовой среде. Есть резервные копии. :)
Я люблю использовать
BEGIN/COMMIT TRANSACTION
его, потому что он предотвращает возмущение других процессов таблицей, пока вы находитесь в процессе ее изменения, и дает вам возможность откатить все назад, если что-то пойдет не так. Однако любой другой процесс, который попытается получить доступ к вашей таблице до того, как вы совершите транзакцию, будет ждать. Это может быть довольно плохо, если у вас большой стол и / или вы находитесь в производственной среде.OUTPUT .. INTO
не сработает, если у вашей целевой таблицы есть ограничения внешнего ключа или какие-либо другие функции, которые я не могу вспомнить из головы. Вместо этого вы можете вместо этого выгрузить данные во временную таблицу, а затем вставить их обратно в исходную таблицу. Возможно, вы сможете использовать переключение разделов (даже если вы не используете разделы).Запускайте эти операторы по одному, а не в виде пакета или хранимой процедуры.
Попробуйте подумать о других вещах, которые могут зависеть от
id
столбца, который вы отбрасываете и воссоздаете. Любые индексы нужно будет удалить и заново создать (как мы делали с первичным ключом). Не забудьте составить сценарий каждого индекса и ограничения, которые вам нужно будет воссоздать заранее.Отключить любые
INSERT
иDELETE
триггеры на столе.Если воссоздание таблицы является вариантом:
Если воссоздание таблицы является вариантом для вас, все намного проще:
id
столбца в видеIDENTITY
,IDENTITY_INSERT ON
для стола,IDENTITY_INSERT OFF
иисточник
IDENTITY_INSERT ON
, заполнить и отключить его. Это то, что я хотел сделать, но не знал, что MSSQL поддерживает это.Использование UPDATE, DELETE или INSERT для перемещения данных может занять довольно много времени и использовать ресурсы (IO) как для данных, так и для файлов журналов / дисков. Можно избежать заполнения журнала транзакций потенциально большим количеством записей при работе с большой таблицей: при использовании переключения разделов изменяются только метаданные.
Движение данных не происходит, и поэтому оно выполняется очень быстро (почти мгновенно).
Образец таблицы
Вопрос не показывает исходную таблицу DDL. Следующий DDL будет использоваться в качестве примера в этом ответе:
С этим запросом добавлено полдюжины фиктивных случайных идентификаторов от 0 до 15:
Пример данных в
IdT
Новый стол с
IDENTITY(0, 1)
Единственной проблемой
idT
является отсутствиеIDENTITY(0, 1)
свойства идентификатора. Новая таблица с аналогичной структурой иIDENTITY(0, 1)
создается:Помимо
IDENTITY(0, 1)
,idT_Switch
идентичноidT
.Иностранные ключи
Внешние ключи
idT
должны быть удалены, чтобы использовать эту технику.Переключатель раздела
idT
ИidT_Switch
таблицы имеют совместимую структуру. Вместо того , чтобы использоватьDELETE
,UPDATE
иINSERT
заявление для перемещения строк изidT
вidT_Switch
или наidT
себе,ALTER TABLE ... SWITCH
может быть использовано:Отдельный «раздел»
PK_idT
(всей таблицы) перемещается вPK_idT_Switch
(и наоборот).idT
теперь содержит 0 строк иidT_Switch
содержит 6 строк.Вы можете найти полный список требований совместимости источника и назначения здесь:
Эффективная передача данных с помощью переключения разделов
Обратите внимание, что это использование
SWITCH
не требует Enterprise Edition, потому что нет явного разделения. Нераспределенная таблица считается таблицей с одним разделом, начиная с SQL Server 2005 и далее.замещать
idT
idT
теперь пусто и бесполезно и может быть удалено:idT_Switch
можно переименовать и заменит старуюidT
таблицу:Внешние ключи
Внешние ключи могут быть снова добавлены в новую
idT
таблицу. Все, что ранее было удалено,idT
чтобы сделать таблицы совместимыми для переключения, также должно быть переделано.Reseed
Эта команда возвращает 0. Таблица idT содержит 6 строк с MAX (id) = 15. DBCC CHECKIDENT (table_name) можно использовать:
Поскольку 15 больше 0, оно будет автоматически перезапущено без поиска MAX (id):
IDENT_CURRENT теперь возвращает 15 .
Протестируйте и добавьте данные
Простое
INSERT
утверждение:Добавляет эту строку:
id
Колонка теперь использует идентификатор и вновь вставлено значение действительно 16 (15 + 1).Дополнительная информация
Здесь есть связанный вопрос и ответ с большим количеством информации о
SWITCH
технике здесь:Почему удаление свойства Identity для столбца не поддерживается
источник
Если вы хотите начать с нового значения идентичности, вам нужно повторно заполнить свою идентичность. Посмотрите документацию для
CHECKIDENT
источник
ENABLE и DISABLE IDENTITY_INSERT
Если ваша таблица TABLE_A, то
источник