Добавление идентификатора в существующий столбец - PullRequest
398 голосов
/ 26 июня 2009

Мне нужно изменить первичный ключ таблицы на столбец идентификаторов, и в таблице уже есть ряд строк.

У меня есть скрипт для очистки идентификаторов, чтобы они были последовательными, начиная с 1, отлично работает на моей тестовой базе данных.

Какая команда SQL изменяет столбец, чтобы иметь свойство идентификации?

Ответы [ 19 ]

436 голосов
/ 26 июня 2009

Нельзя изменить существующие столбцы для идентификации.

У вас есть 2 варианта,

  1. Создать новую таблицу с идентификатором и удалить существующую таблицу

  2. Создать новый столбец с идентификатором и удалить существующий столбец

Подход 1. ( Новая таблица ) Здесь вы можете сохранить существующие значения данных во вновь созданном столбце идентификаторов.

CREATE TABLE dbo.Tmp_Names
    (
      Id int NOT NULL
             IDENTITY(1, 1),
      Name varchar(50) NULL
    )
ON  [PRIMARY]
go

SET IDENTITY_INSERT dbo.Tmp_Names ON
go

IF EXISTS ( SELECT  *
            FROM    dbo.Names ) 
    INSERT  INTO dbo.Tmp_Names ( Id, Name )
            SELECT  Id,
                    Name
            FROM    dbo.Names TABLOCKX
go

SET IDENTITY_INSERT dbo.Tmp_Names OFF
go

DROP TABLE dbo.Names
go

Exec sp_rename 'Tmp_Names', 'Names'

Подход 2 ( Новый столбец ) Нельзя сохранить существующие значения данных во вновь созданном столбце идентификаторов. Столбец идентификаторов будет содержать последовательность чисел.

Alter Table Names
Add Id_new Int Identity(1, 1)
Go

Alter Table Names Drop Column ID
Go

Exec sp_rename 'Names.Id_new', 'ID', 'Column'

Подробнее см. В следующем сообщении на форуме по Microsoft SQL Server:

Как изменить столбец на тождество (1,1)

184 голосов
/ 13 ноября 2009

В SQL 2005 и выше есть хитрость для решения этой проблемы без изменения страниц данных таблицы. Это важно для больших таблиц, где прикосновение к каждой странице данных может занять минуты или часы. Трюк также работает, даже если столбец идентификаторов является первичным ключом, является частью кластеризованного или некластеризованного индекса или других ошибок, которые могут привести к путанице в более простом решении «добавить / удалить / переименовать столбец».

Вот хитрость: вы можете использовать оператор SQL Server ALTER TABLE ... SWITCH , чтобы изменить схему таблицы без изменения данных, то есть вы можете заменить таблицу идентификатором на идентичную таблицу схема, но без столбца IDENTITY. Тот же трюк работает для добавления IDENTITY в существующий столбец.

Обычно ALTER TABLE ... SWITCH используется для эффективной замены полного раздела в многораздельной таблице новым пустым разделом. Но его также можно использовать и в однораздельных таблицах.

Я использовал этот трюк, чтобы менее чем за 5 секунд преобразовать столбец таблицы из 2,5 миллиардов строк из IDENTITY в не-IDENTITY (чтобы выполнить многочасовой запрос, план запроса которого работал лучше для столбцы без идентификатора), а затем восстановил настройку IDENTITY, снова менее чем за 5 секунд.

Вот пример кода того, как это работает.

 CREATE TABLE Test
 (
   id int identity(1,1),
   somecolumn varchar(10)
 );

 INSERT INTO Test VALUES ('Hello');
 INSERT INTO Test VALUES ('World');

 -- copy the table. use same schema, but no identity
 CREATE TABLE Test2
 (
   id int NOT NULL,
   somecolumn varchar(10)
 );

 ALTER TABLE Test SWITCH TO Test2;

 -- drop the original (now empty) table
 DROP TABLE Test;

 -- rename new table to old table's name
 EXEC sp_rename 'Test2','Test';

 -- update the identity seed
 DBCC CHECKIDENT('Test');

 -- see same records
 SELECT * FROM Test; 

Это, очевидно, более сложная задача, чем решения в других ответах, но если ваша таблица большая, это может спасти жизнь. Есть несколько предостережений:

  • Насколько я знаю, идентичность - это единственное, что вы можете изменить в столбцах таблицы с помощью этого метода. Добавление / удаление столбцов, изменение обнуляемости и т. Д. Запрещено.
  • Вам нужно будет сбросить чужие ключи перед тем, как переключаться, и восстановить их после.
  • То же самое для функций С СХЕМАМИ, видов и т. Д.
  • индексы новой таблицы должны точно совпадать (те же столбцы, тот же порядок и т. Д.)
  • Старые и новые таблицы должны находиться в одной файловой группе.
  • Работает только на SQL Server 2005 или более поздней версии
  • Ранее я считал, что этот трюк работает только в редакциях SQL Server для Enterprise или Developer (поскольку разделы поддерживаются только в версиях Enterprise и Developer), но Мейсон Жвити в своем комментарии ниже говорит, что он также работает в стандарте SQL Издание тоже. Я предполагаю, что это означает, что ограничение Enterprise или Developer не распространяется на ALTER TABLE ... SWITCH.

На TechNet есть хорошая статья, подробно описывающая требования выше.

ОБНОВЛЕНИЕ - Эрик Ву прокомментировал ниже, что добавляет важную информацию об этом решении. Скопируйте его сюда, чтобы убедиться, что он привлекает больше внимания:

Здесь есть еще одна оговорка, о которой стоит упомянуть. Хотя новая таблица с радостью получит данные из старой таблицы, а все новые строки будут вставлены в соответствии с шаблоном идентификации, они будут начинаться с 1 и потенциально прерываться, если указанный столбец является первичным ключом. Попробуйте запустить DBCC CHECKIDENT('<newTableName>') сразу после переключение. См. msdn.microsoft.com / en-us / library / ms176057.aspx для получения дополнительной информации. Информация.

Если таблица активно расширяется новыми строками (то есть у вас не так много простоев между добавлением IDENTITY и добавлением новых строк, тогда вместо DBCC CHECKIDENT вы захотите вручную установить начальное значение идентификатора в новая схема таблицы будет больше, чем самый большой существующий идентификатор в таблице, например, IDENTITY (2435457, 1). Возможно, вы сможете включить в транзакцию ALTER TABLE...SWITCH и DBCC CHECKIDENT (или нет - не проверяли это ) но, похоже, установка начального значения вручную будет проще и безопаснее.

Очевидно, что если в таблицу не добавляются новые строки (или они добавляются только изредка, например, ежедневный процесс ETL), то это условие гонки не будет выполнено, поэтому DBCC CHECKIDENT в порядке.

64 голосов
/ 26 июня 2009

Вы не можете изменить столбец на столбец IDENTITY. Что вам нужно сделать, это создать новый столбец, который определяется как IDENTITY с самого начала, затем отбросить старый столбец и переименовать новый в старое имя.

ALTER TABLE (yourTable) ADD NewColumn INT IDENTITY(1,1)

ALTER TABLE (yourTable) DROP COLUMN OldColumnName

EXEC sp_rename 'yourTable.NewColumn', 'OldColumnName', 'COLUMN'

Марк

14 голосов
/ 24 августа 2011

Вот классное решение, описанное здесь: SQL SERVER - Добавить или удалить свойство идентификации в столбце

Короче говоря, отредактируйте вручную таблицу в SQL Manager, поменяйте личность, НЕ СОХРАНЯЙТЕ изменения, просто покажите сценарий, который будет создан для изменений, скопируйте его и используйте позже.

Это значительно экономит время, поскольку он (скрипт) содержит все внешние ключи, индексы и т. Д., Относящиеся к изменяемой вами таблице. Написание этого вручную ... Не дай Бог.

6 голосов
/ 29 декабря 2014

Простое объяснение

Переименуйте существующий столбец, используя sp_RENAME

EXEC sp_RENAME 'Table_Name.Existing_ColumnName', 'New_ColumnName', 'COLUMN'

Пример для переименования:

Существующий столбец UserID переименован в OldUserID

EXEC sp_RENAME 'AdminUsers.UserID' , 'OldUserID', 'COLUMN'

Затем добавьте новый столбец, используя запрос alter, чтобы установить в качестве первичного ключа и значение идентификатора

ALTER TABLE TableName ADD Old_ColumnName INT NOT NULL PRIMARY KEY IDENTITY(1,1)

Пример установки первичного ключа

Имя нового созданного столбца - UserID

ALTER TABLE Users ADD UserID INT NOT NULL PRIMARY KEY IDENTITY(1,1)

затем бросьте переименованную колонку

ALTER TABLE Table_Name DROP COLUMN Renamed_ColumnName

Пример удаления переименованного столбца

ALTER TABLE Users DROP COLUMN OldUserID

Теперь мы добавляем первичный ключ и идентификатор в существующий столбец таблицы.

6 голосов
/ 23 июня 2015

Попробуйте использовать ПОСЛЕДОВАТЕЛЬНОСТЬ вместо ИДЕНТИЧНОСТИ .

В SQL Server 2014 (я не знаю о более низких версиях) вы можете сделать это просто, используя последовательность.

CREATE SEQUENCE  sequence_name START WITH here_higher_number_than_max_existed_value_in_column INCREMENT BY 1;

ALTER TABLE table_name ADD CONSTRAINT constraint_name DEFAULT NEXT VALUE FOR sequence_name FOR column_name

Отсюда: Последовательность в качестве значения по умолчанию для столбца

5 голосов
/ 30 августа 2013

Я - Java-разработчик, который попал в команду без администратора и в которой я не могу получить права администратора. Передо мной стояла задача переместить всю схему между двумя базами данных, поэтому без администратора базы данных мне пришлось делать это и делать это с помощью сценариев, поскольку я не мог использовать графический интерфейс пользователя в SQL Server 2008, поскольку у меня не было прав администратора.

Все было перемещено без проблем, однако при запуске хранимой процедуры в новой schema.table я обнаружил, что потерял поле идентификатора в таблице. Я дважды проверил скрипт, который создал таблицу, и он был там, однако, SQL Server не получил его, когда я запустил скрипт. Позже мне сказал администратор БД, что он видел эту же проблему раньше.

В любом случае для SQL Server 2008 я предпринял следующие шаги, чтобы решить эту проблему, и они сработали, поэтому я публикую это здесь в надежде, что это кому-нибудь поможет. Это то, что я сделал, поскольку у меня были зависимости FK от другой таблицы, что усложнило задачу:

Я использовал этот запрос, чтобы убедиться, что удостоверение действительно отсутствует, и просмотреть зависимости от таблицы.

1.) Найти статистику по таблице:

exec sp_help 'dbo.table_name_old';

2.) Создайте дубликат идентичной новой таблицы, за исключением того, что добавьте поле идентификатора в поле PK, где оно было раньше.

3.) Отключить удостоверение для перемещения данных.

SET IDENTITY_INSERT dbo.table_name ON 

4.) Передача данных.

INSERT INTO dbo.table_name_new
(
field1, field2, etc...
)
SELECT 
field1, field2, etc...
FROM 
dbo.table_name_old;

5.) Убедитесь, что данные есть.

SELECT * FROM dbo.table_name_new

6.) Повторно активируйте личность.

SET IDENTITY_INSERT ToyRecP.ToyAwards.lkpFile_New OFF

7.) Это лучший сценарий, который я нашел, чтобы получить все отношения FK для проверки того, на какие таблицы исходная таблица ссылается как на зависимости и я сталкивался со многими, так что это хранитель!

SELECT f.name AS ForeignKey,
   OBJECT_NAME(f.parent_object_id) AS TableName,
   COL_NAME(fc.parent_object_id, fc.parent_column_id) AS ColumnName,
   OBJECT_NAME (f.referenced_object_id) AS ReferenceTableName,
   COL_NAME(fc.referenced_object_id, fc.referenced_column_id) AS ReferenceColumnName
FROM sys.foreign_keys AS f
INNER JOIN sys.foreign_key_columns AS fc
   ON f.OBJECT_ID = fc.constraint_object_id
   ORDER BY ReferenceTableName;

8.) Перед следующим шагом убедитесь, что у вас есть все сценарии PK и FK для всех задействованных таблиц.

9.) Вы можете щелкнуть правой кнопкой мыши по каждому ключу и написать скрипт, используя SQL Server 2008

10.) Удалить FK из таблицы зависимостей, используя следующий синтаксис:

ALTER TABLE [dbo].[table_name] DROP CONSTRAINT [Name_of_FK]

11.) Оставьте исходный стол:

DROP TABLE dbo.table_name_old;

13.) Следующие шаги основаны на сценариях, которые вы создали в SQL Server 2008 на шаге 9.

- Добавить PK в новую таблицу.

- добавить FK к новой таблице.

- Добавить ФК обратно в таблицу зависимостей.

14.) Убедитесь, что все правильно и полно. Я использовал графический интерфейс для просмотра таблиц.

15.) Переименуйте новую таблицу в исходное имя таблицы.

exec sp_RENAME '[Schema_Name.OldTableName]' , '[NewTableName]';

Наконец-то все заработало!

3 голосов
/ 02 февраля 2016

Как я понял в обычных случаях, мы создаем таблицу с Первичным ключом , который имеет Свойство Identity
Поэтому Переименовать или Удалить столбец, связанный с Первичным ключом ограничение , будет невозможно, поскольку правила ограничения проверяют структуру столбца. < бр /> Чтобы достичь этого, мы должны обработать некоторые шаги следующим образом:
Предположим, что TableName = 'Employee' и ColumnName = 'EmployeeId'

1. Добавьте новый столбец EmployeeId_new в таблицу Employee.
ALTER TABLE Employee ADD EmployeeId_new INT IDENTITY (1,1)

  1. Теперь удалите столбец «EmployeeId» из таблицы «Employee»
    ALTER TABLE Сотрудник DROP COLUMN EmployeeId

  2. Это вызовет ошибку, потому что применяются правила ограничения первичного ключа и проверки структуры столбца.
    * ### ' Сообщение 5074, Уровень 16, Состояние 1, Строка 1 Объект [PK_dbo.Employee] зависит от столбца [EmployeeId].' ###

  3. Таким образом, мы должны сначала удалить ограничение первичного ключа из таблицы «Сотрудник», затем мы можем удалить столбец
    ALTER TABLE Ограничение DROP сотрудника [PK_dbo.Employee]

  4. Теперь мы можем удалить столбец EmployeeId из таблицы Employee, как это делалось на предыдущем шаге, где мы получили ошибку
    ALTER TABLE Сотрудник DROP COLUMN EmployeeId

  5. Теперь столбец EmployeeId удален из таблицы. Таким образом, мы переименуем новый добавленный новый столбец EmployeeId_new в EmployeeId.
    sp_rename 'Employee.EmployeeId', 'EmployeeId_new', 'COLUMN'

  6. Чтобы переставить таблицу в том же виде, в каком она была, мы должны добавить ограничение основного ключа для столбца «EmployeeId»
    ALTER TABLE Первичный ключ для ограничения добавления сотрудника [PK_dbo.Employee] (EmployeeId)

8. Теперь таблица 'Employee' с 'EmployeeId' модифицируется для правил идентификации вместе с существующим ограничением первичного ключа

3 голосов
/ 26 июня 2009

По замыслу не существует простого способа включить или отключить функцию идентификации для существующего столбца. Единственный чистый способ сделать это - создать новый столбец и сделать его столбцом идентификаторов или создать новую таблицу и перенести ваши данные.

Если мы используем SQL Server Management Studio, чтобы избавиться от значения идентификатора в столбце «id», создается новая временная таблица, данные перемещаются во временную таблицу, старая таблица удаляется, а новая таблица переименовывается. .

Используйте Management Studio, чтобы внести изменения, затем щелкните правой кнопкой мыши в конструкторе и выберите «Создать сценарий изменения».

Вы увидите, что это то, что SQL-сервер делает в фоновом режиме.

3 голосов
/ 26 июня 2009

вы не можете сделать это так, вам нужно добавить другой столбец, удалить исходный столбец и переименовать новый столбец или создать новую таблицу, скопировать данные и удалить старую таблицу с последующим переименованием новой таблицы к старому столу

если вы используете SSMS и в конструкторе задаете для свойства идентификации значение ON, то SQL Server делает это за кулисами. Так что если у вас есть таблица с именем [user], это то, что произойдет, если вы сделаете UserID и идентификатор

BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION

GO

GO
CREATE TABLE dbo.Tmp_User
    (
    UserID int NOT NULL IDENTITY (1, 1),
    LastName varchar(50) NOT NULL,
    FirstName varchar(50) NOT NULL,
    MiddleInitial char(1) NULL

    )  ON [PRIMARY]
GO

SET IDENTITY_INSERT dbo.Tmp_User ON
GO
IF EXISTS(SELECT * FROM dbo.[User])
 EXEC('INSERT INTO dbo.Tmp_User (UserID, LastName, FirstName, MiddleInitial)
    SELECT UserID, LastName, FirstName, MiddleInitialFROM dbo.[User] TABLOCKX')
GO
SET IDENTITY_INSERT dbo.Tmp_User OFF
GO

GO
DROP TABLE dbo.[User]
GO
EXECUTE sp_rename N'dbo.Tmp_User', N'User', 'OBJECT'
GO
ALTER TABLE dbo.[User] ADD CONSTRAINT
    PK_User PRIMARY KEY CLUSTERED 
    (
    UserID
    ) ON [PRIMARY]

GO
COMMIT

Сказав, что есть способ взломать системную таблицу, чтобы выполнить ее, установив побитовое значение, но это не поддерживается, и я бы не стал это делать

...