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

160

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

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

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

ID = ID + 1

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

Невозможно обновить идентификационный столбец «ID».

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

    ALTER TABLE Test NOCHECK CONSTRAINT ALL 
    set identity_insert ID ON

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

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

Томаш Смыковский
источник

Ответы:

220

Тебе надо

set identity_insert YourTable ON

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

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

set identity_insert YourTable OFF
Аляска
источник
133
настройка будет работать только при вставке данных, а не при обновлении. Оператор ОБНОВЛЕНИЯ все еще потерпит неудачу.
Хусейн Ронцевич
31
Для обновления необходимо удалить и заново вставить. Другого пути нет.
ashes999
1
@MartinSmith ваше решение кажется слишком длинным. Возможность сделать это в два этапа (идентификация, удаление / вставка, идентификация) гораздо эффективнее.
ashes999
3
@ ashes999 Это 4 шага, а не 2. Мой ответ - только еще один (создание таблицы, переключение, обновление, переключение назад, удаление). Вероятно, вы более знакомы с этими шагами, поэтому они выглядят менее запутанными. Обновление может быть гораздо более эффективным, чем удаление вставки, когда задействовано много строк. Кроме того, где вы держите удаленные строки? Если #tempтаблица, которую вы затем отбрасываете, это еще один шаг, который вы не учитывали здесь.
Мартин Смит
40

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
Мартин Смит
источник
1
Очень гладко Каждый день узнавайте что-то новое (кстати, я проверял это на SQLExpress; несмотря на то, что SWITCH TO не использует разбиение, по-видимому). Обратите внимание, что таблица должна очень точно совпадать (индексы, ФК и т. Д.)
Марк Совул
1
Работает ли метод switch, когда у вас есть PK, FKs, Index и Views, построенные на исходной таблице? Будут ли они сломаться с помощью этого метода?
TJ
1
@tj при создании сценария временной таблицы из исходной таблицы, включая все индексы и ограничения. Затем измените имена таблицы и ограничения, чтобы избежать коллизий. Представления не вызовут проблемы, если они не проиндексированы или не привязаны к схеме.
Мартин Смит
Не работает, если в таблице есть индекс полнотекстового поиска. Я предполагаю, что возможно удалить это и воссоздать это впоследствии, но я не проверял.
Юлен
26

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

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

UPDATE table SET Id = Id + 1

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

Майкл Прайор
источник
3
Если вы вносите изменения вручную, вы можете попросить менеджера сгенерировать сценарий SQL для изменения (меню дизайнера таблиц, сценарий создания изменений). Для этого изменения он создает новую таблицу и копирует данные, а затем удаляет оригинал.
Робин Беннетт
2
@tomaszs - пример кода , который также является более эффективным , поскольку он не физически восстановить таблицу на всех (это будет делать это дважды) в моем конце ответа здесь
Мартин Смит
Вы не можете добавить личность обратно. Вы? stackoverflow.com/questions/1049210/…
Томас Кубес
Спасибо. Это было прекрасно. У меня была 1 строка в моей таблице, о которой я не знал, поэтому в моих скриптах начальной загрузки для моей таблицы Idзначения Auto Identity были отключены на 1.
Шива
18

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

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

Майлз Д
источник
9

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

Идея

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

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

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

Роксана
источник
4

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

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

удачи!

Кристофер Кляйн
источник
1

Изменение идентичности может завершиться неудачей в зависимости от ряда факторов, в основном вращающихся вокруг объектов / отношений, связанных со столбцом id. Кажется, что дизайн БД так же важен, как и ID, если они вообще меняются, редко, если они меняются (я уверен, что у вас есть свои причины и вы делаете изменения). Если вам действительно нужно время от времени менять идентификаторы, я бы предложил создать новый столбец фиктивных идентификаторов, который не является первичным ключом / автономным номером, которым вы можете управлять самостоятельно и генерировать из текущих значений. С другой стороны, идея Chrisotphers выше была бы моим другим предложением, если у вас есть проблемы с разрешением вставки идентификационной информации.

Удачи

PS это не сбой, потому что последовательный порядок, в котором он выполняется, пытается обновить значение в списке до элемента, который уже существует в списке идентификаторов? хватаясь за соломинку, возможно, добавьте количество строк + 1, затем, если это сработает, вычтите количество строк: -S

дубильщик
источник
1

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

Робин Беннетт
источник
1

Вы можете вставить новые строки с измененными значениями, а затем удалить старые строки. В следующем примере идентификатор изменения должен совпадать с внешним ключом 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

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

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.

Ogglas
источник
0

Я видел хорошую статью, которая помогла мне в последний момент ... Я пытался вставить несколько строк в таблицу, в которой был столбец идентификаторов, но сделал это неправильно и пришлось удалить обратно. Как только я удалил строки, мой столбец идентификаторов изменился. Я пытался найти способ обновить столбец, который был вставлен, но - не повезло. Итак, при поиске в гугле нашел ссылку ..

  1. Удалил столбцы, которые были вставлены неправильно
  2. Использовать принудительную вставку, используя идентификацию вкл / выкл (объяснено ниже)

http://beyondrelational.com/modules/2/blogs/28/posts/10337/sql-server-how-do-i-insert-an-explicit-value-into-an-identity-column-how-do- я-обновление-заместитель стоимости из-an.aspx

Балу
источник
1
Не уверен, что вы действительно ответили на вопрос здесь, хотя.
Эндрю Барбер
0

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

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

SET IDENTITY_INSERT Emp_tb_gb_Menu ON
     INSERT Emp_tb_gb_Menu(MenuID) VALUES (68)
SET IDENTITY_INSERT Emp_tb_gb_Menu OFF

http://allinworld99.blogspot.com/2016/07/how-to-edit-identity-field-in-sql.html

Асит Радж
источник