Как программно изменить значения столбца идентификаторов? - PullRequest
158 голосов
/ 15 апреля 2009

У меня есть база данных MS SQL 2005 с таблицей Test со столбцом ID. ID - это столбец идентификаторов.

У меня есть строки в этой таблице, и все они имеют соответствующие ID автоматически увеличенные значения.

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

ID = ID + 1

Но когда я делаю это, я получаю ошибку:

Невозможно обновить идентификатор столбца 'ID'.

Я пробовал это:

    ALTER TABLE Test NOCHECK CONSTRAINT ALL 
    set identity_insert ID ON

Но это не решает проблему.

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

Ответы [ 13 ]

217 голосов
/ 27 июля 2009

Вам нужно

set identity_insert YourTable ON

Затем удалите строку и заново вставьте ее под другим именем.

Как только вы закончите вставку, не забудьте выключить identity_insert

set identity_insert YourTable OFF
40 голосов
/ 22 июня 2013

IDENTITY значения столбца неизменны.

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

Предполагая следующую структуру

CREATE TABLE Test
(
ID INT IDENTITY(1,1) PRIMARY KEY,
X VARCHAR(10)
)

INSERT INTO Test 
OUTPUT INSERTED.*
SELECT 'Foo' UNION ALL
SELECT 'Bar' UNION ALL
SELECT 'Baz'

Тогда вы можете сделать

/*Define table with same structure but no IDENTITY*/
CREATE TABLE Temp
(
ID INT PRIMARY KEY,
X VARCHAR(10)
)

/*Switch table metadata to new structure*/
ALTER TABLE Test SWITCH TO Temp;

/*Do the update*/
UPDATE Temp SET ID = ID + 1;

/*Switch table metadata back*/
ALTER TABLE Temp SWITCH TO Test;

/*ID values have been updated*/
SELECT *
FROM Test

/*Safety check in case error in preceding step*/
IF NOT EXISTS(SELECT * FROM Temp)
    DROP TABLE Temp /*Drop obsolete table*/

В SQL Server 2012 возможно иметь столбец с автоинкрементом, который также может быть обновлен более просто с помощью SEQUENCES

CREATE SEQUENCE Seq
    AS INT
    START WITH 1
    INCREMENT BY 1

CREATE TABLE Test2
(
ID INT DEFAULT NEXT VALUE FOR Seq NOT NULL PRIMARY KEY,
X VARCHAR(10)
)

INSERT INTO Test2(X)
SELECT 'Foo' UNION ALL
SELECT 'Bar' UNION ALL
SELECT 'Baz'

UPDATE Test2 SET ID+=1
26 голосов
/ 15 апреля 2009

С помощью пользовательского интерфейса в диспетчере SQL Server 2005 измените столбец, удалите свойство столбца autonumber (identity) (выберите таблицу, щелкнув ее правой кнопкой мыши и выберите «Дизайн»).

Затем запустите ваш запрос:

UPDATE table SET Id = Id + 1

Затем добавьте свойство autonumber обратно в столбец.

18 голосов
/ 15 апреля 2009

Во-первых, установка IDENTITY_INSERT в этом случае не будет работать для того, что вам требуется (оно используется для вставки новых значений, таких как пробелы в пробках).

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

9 голосов
/ 30 августа 2012

Это можно сделать с помощью временной таблицы.

Идея

  • отключить ограничения (если на ваш идентификатор ссылается внешний ключ)
  • создать временную таблицу с новым идентификатором
  • удалить содержимое таблицы
  • копировать обратно данные из скопированной таблицы в исходную таблицу
  • включить предварительно отключенные ограничения

SQL-запросы

Допустим, у вашей таблицы test есть два дополнительных столбца (column2 и column3) и что есть 2 таблицы с внешними ключами, ссылающимися на test, называемые foreign_table1 и foreign_table2 (поскольку проблемы реальной жизни никогда не бывает простым).

alter table test nocheck constraint all;
alter table foreign_table1 nocheck constraint all;
alter table foreign_table2 nocheck constraint all;
set identity_insert test on;

select id + 1 as id, column2, column3 into test_copy from test v;
delete from test;
insert into test(id, column2, column3)
select id, column2, column3 from test_copy

alter table test check constraint all;
alter table foreign_table1 check constraint all;
alter table foreign_table2 check constraint all;
set identity_insert test off;
drop table test_copy;

Вот и все.

6 голосов
/ 12 апреля 2012

DBCC CHECKIDENT («databasename.dbo.orders», RESEED, 999) Вы можете изменить любой номер столбца идентификатора с помощью этой команды, а также вы можете начать этот номер поля с любого числа, которое вы хотите. Например, в моей команде я прошу начать с 1000 (999 + 1) надеюсь, что этого будет достаточно ... удачи

4 голосов
/ 15 апреля 2009

Если столбец не является PK, вы всегда можете создать НОВЫЙ столбец в таблице с увеличенными числами, отбросить оригинал, а затем заменить новый на старый.

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

удачи!

1 голос
/ 08 августа 2016

Сначала сохраните все идентификаторы и программно измените их на значения, которые вы не хотите, затем удалите их из базы данных, а затем вставьте их снова, используя нечто похожее:

use [Name.Database]
go
set identity_insert [Test] ON
insert into [dbo].[Test]
           ([Id])
     VALUES
           (2)
set identity_insert [Test] OFF

Для массового использования:

use [Name.Database]
go
set identity_insert [Test] ON
BULK INSERT [Test]
FROM 'C:\Users\Oscar\file.csv'
WITH (FIELDTERMINATOR = ';',
      ROWTERMINATOR = '\n',
      KEEPIDENTITY)
set identity_insert [Test] OFF

Пример данных из файла file.csv:

2;
3;
4;
5;
6;

Если вы не отключите identity_insert, вы получите следующую ошибку:

Невозможно вставить явное значение для столбца идентификаторов в таблице «Тест», когда Для параметра IDENTITY_INSERT установлено значение OFF.

1 голос
/ 06 февраля 2015

Вы можете вставить новые строки с измененными значениями, а затем удалить старые строки. В следующем примере идентификатор изменения должен совпадать с внешним ключом PersonId

SET IDENTITY_INSERT [PersonApiLogin] ON

INSERT INTO [PersonApiLogin](
       [Id]
      ,[PersonId]
      ,[ApiId]
      ,[Hash]
      ,[Password]
      ,[SoftwareKey]
      ,[LoggedIn]
      ,[LastAccess])
SELECT [PersonId]
      ,[PersonId]
      ,[ApiId]
      ,[Hash]
      ,[Password]
      ,[SoftwareKey]
      ,[LoggedIn]
      ,[LastAccess]
FROM [db304].[dbo].[PersonApiLogin]
GO

DELETE FROM [PersonApiLogin]
WHERE [PersonId] <> ID
GO
SET IDENTITY_INSERT [PersonApiLogin] OFF
GO
1 голос
/ 27 июля 2009

Если вам необходимо время от времени менять идентификаторы, лучше не использовать столбец идентификаторов. В прошлом мы реализовывали поля автонумерации вручную, используя таблицу «Счетчики», которая отслеживает следующий идентификатор для каждой таблицы. IIRC мы сделали это, потому что столбцы идентификаторов вызывали повреждение базы данных в SQL2000, но возможность изменения идентификаторов иногда была полезна для тестирования.

...