プログラムでID列の値を変更するにはどうすればよいですか?


160

Test列を持つテーブルを含むMS SQL 2005データベースがありますIDIDID列です。

このテーブルに行があり、それらすべてに対応するIDの自動インクリメント値があります。

次に、このテーブルのすべてのIDを次のように変更します。

ID = ID + 1

しかし、これを行うとエラーが発生します。

ID列 'ID'を更新できません。

私はこれを試しました:

    ALTER TABLE Test NOCHECK CONSTRAINT ALL 
    set identity_insert ID ON

しかし、これは問題を解決しません。

この列にIDを設定する必要がありますが、値も時々変更する必要があります。だから私の質問は、このタスクを達成する方法です。

回答:


220

必要がある

set identity_insert YourTable ON

次に、行を削除して、別のIDで再挿入します。

挿入が完了したら、identity_insertをオフにすることを忘れないでください。

set identity_insert YourTable OFF

133
これを設定すると、データを挿入するときにのみ機能し、更新時には機能しません。UPDATEステートメントは引き続き失敗します。
フセインロンセビッチ2011

31
アップデートの場合は、削除して再挿入する必要があります。他に方法はありません。
ashes999 2013

1
@MartinSmithソリューションが長すぎるようです。2つのステップ(識別オフ、削除/挿入、識別オン)でそれを実行できることは、はるかに効果的です。
ashes999 2013

3
@ ashes999これは2つのステップではなく4つのステップです。私の答えはもう1つだけです(テーブルの作成、切り替え、更新、元に戻す、ドロップ)。更新は、多くの行が関係する場合は、挿入を削除してから削除する方がはるかに効率的です。また、削除された行をどこに保持していますか?#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でこれをテストしました。SWITCHTOにも関わらず、パーティション分割は使用していないようです)。テーブルはかなり正確に一致する必要があることに注意してください(インデックス、FKなど)
Mark Sowul

1
元のテーブルに基づいてPK、FK、インデックス、およびビューを作成した場合、switchメソッドは機能しますか?彼らはこの方法を使用することで壊れますか?
TJ

1
@tjすべてのインデックスと制約を含むソーステーブルから一時テーブルスクリプトを作成するとき。次に、テーブルと制約の名前を変更して、衝突を回避します。インデックス付きまたはスキーマバインドでない限り、ビューは問題を引き起こしません。
マーティン・スミス

テーブルに全文検索インデックスがある場合は機能しません。削除して後で再作成することは可能だと思いますが、テストしていません。
youen

26

SQL Server 2005マネージャーのUIを使用して、列を変更し、列の自動番号(ID)プロパティを削除します(テーブルを右クリックして選択し、[デザイン]を選択します)。

次に、クエリを実行します。

UPDATE table SET Id = Id + 1

次に、autonumberプロパティを列に追加します。


3
変更を手動で行う場合、マネージャーに変更のSQLスクリプトを生成するよう依頼できます(テーブルデザイナメニュー、変更スクリプトの生成)。この変更では、新しいテーブルを作成してデータをコピーし、元のテーブルを削除します。
ロビンベネット

2
@tomaszs-テーブルを物理的にまったく再構築しない(これにより2回実行される)ため、より効率的なコード例がここの
Martin Smith

IDを元に戻すことはできません。あなたは?stackoverflow.com/questions/1049210/...
トマスKubes

ありがとう。これは完璧でした。テーブルに気付かなかった1行があったため、テーブルのブートストラップスクリプトのId自動ID値が1オフ
Shiva

18

まず、IDENTITY_INSERTのオンまたはオフの設定は、必要な場合には機能しません(ギャップの差し込みなどの新しい値の挿入に使用されます)。

GUIから操作を行うと、一時テーブルが作成され、すべてのデータがIDフィールドのない新しいテーブルにコピーされ、テーブルの名前が変更されます。


9

これは、一時テーブルを使用して行うことができます。

アイデア

  • 制約を無効にする(IDが外部キーによって参照されている場合)
  • 新しいIDで一時テーブルを作成する
  • テーブルの内容を削除する
  • コピーしたテーブルから元のテーブルにデータをコピーする
  • 事前に無効にした制約を有効にする

SQLクエリ

レッツは、あなたの言うtestテーブルが2つの追加列(持っている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)このコマンドでID列番号を変更できます。また、必要なすべての番号からそのフィールド番号を開始できます。たとえば、私のコマンドでは、 1000(999 + 1)それが十分であることを願って...幸運


4

列がPKでない場合は、常に番号が増分された新しい列をテーブルに作成し、元の列を削除してから、新しい列を古い列に変更できます。

なぜこれを行う必要があるのか​​不思議に思っています... Identityの列をいじる必要があったことのほとんどは、数値を埋め戻すことでしたが、結局DBCC CHECKIDENT(tablename、RESEED、newnextnumber)を使用してしまいました

幸運を!


1

IDの変更は、主にid列にリンクされたオブジェクト/関係を中心に展開するいくつかの要因に応じて失敗する可能性があります。ここではdbの設計が問題になっているようですが、IDが変更されたとしてもめったにありません(理由があり、変更を連鎖させていると確信しています)。実際にIDを変更する必要がある場合は、自分で管理して現在の値から生成できる主キー/自動番号ではない新しいダミーID列を作成することをお勧めします。または、IDの挿入を許可する際に問題が発生した場合、上記のChrisotphersのアイデアが私のもう1つの提案になります。

幸運を

PSそれが実行されている連続した順序がリストの値を既にIDのリストに存在するアイテムに更新しようとしているため、失敗していませんか?ストローをつかんで、おそらく行数+1を加え、それが機能する場合は行数を減算します:-S


1

IDをときどき変更する必要がある場合は、ID列を使用しないことをお勧めします。以前は、各テーブルの次のIDを追跡する「Counters」テーブルを使用して、自動番号フィールドを手動で実装しました。IIRCを使用した理由は、ID列がSQL2000でデータベースの破損を引き起こしていたためですが、IDを変更できることは、テストに役立つことがあります。


1

値が変更された新しい行を挿入してから、古い行を削除できます。次の例では、IDを外部キー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

最初にすべてのIDを保存し、プログラムで不要な値に変更してから、データベースから削除してから、同様のものを使用して再度挿入します。

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に設定されている場合、テーブル 'Test'のID列に明示的な値を挿入できません。


0

私は最後の瞬間に私を助けてくれた良い記事を見ました..私は、ID列があるテーブルにいくつかの行を挿入しようとしましたが、間違ってそれを削除しなければなりませんでした。行を削除すると、ID列が変更されました。挿入された列を更新する方法を見つけようとしましたが、うまくいきませんでした。それで、グーグルで検索している間、リンクを見つけました..

  1. 誤って挿入された列を削除しました
  2. IDのオン/オフを使用して強制挿入を使用する(以下で説明)

http://beyondrelational.com/modules/2/blogs/28/posts/10337/sql-server-how-do-i-insert-an-explicit-value-into-an-identity-column-how-do- i-update-the-value-of-an.aspx


1
ただし、ここで質問に本当に答えたかどうかはわかりません。
アンドリューバーバー

0

非常に良い質問は、まず我々はする必要が上のことは、INSERTクエリを実行した後に(列名を指定する必要があります)、特定のテーブルのIDENTITY_INSERT。

注: ID列を編集した後、IDENTITY_INSERT をオフにすることを忘れないでください。そうしないと、他のテーブルのID列を編集できません。

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.