web-dev-qa-db-ja.com

SQL Server、データ損失なしでテーブルを作成した後に自動増分を設定する方法は?

テーブルがありますtable1 SQL Server 2008では、レコードが含まれています。

主キーが必要ですtable1_Sno列は自動インクリメント列になります。これは、データ転送やテーブルのクローンなしで実行できますか?

ALTER TABLEを使用して自動インクリメント列を追加できることは知っていますが、主キーである既存の列にAUTO_INCREMENTオプションを単純に追加できますか?

47
Shankar

IDENTITYプロパティの変更は、実際にはメタデータのみの変更です。ただし、メタデータを直接更新するには、インスタンスをシングルユーザーモードで起動し、sys.syscolparsおよび文書化されていない/サポートされていないものであり、私が推奨するものや追加の詳細を提供するものではありません。

SQL Server 2012+でこの答えに出くわした人にとって、自動インクリメント列のこの結果を達成する最も簡単な方法は、SEQUENCEオブジェクトを作成し、next value for seqを列のデフォルトとして。

または、以前のバージョン(2005年以降)の this connect item に記載されている回避策は、ALTER TABLE...SWITCH。また、MSDN here でブログを書いています。これを達成するためのコードはそれほど単純ではなく、制限があります-変​​更されるテーブルは外部キー制約の対象になり得ないなど。

サンプルコード。

identity列のないテストテーブルをセットアップします。

CREATE TABLE dbo.tblFoo 
(
bar INT PRIMARY KEY,
filler CHAR(8000),
filler2 CHAR(49)
)


INSERT INTO dbo.tblFoo (bar)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM master..spt_values v1, master..spt_values v2

identity列を持つように変更します(多かれ少なかれインスタント)。

BEGIN TRY;
    BEGIN TRANSACTION;

    /*Using DBCC CHECKIDENT('dbo.tblFoo') is slow so use dynamic SQL to
      set the correct seed in the table definition instead*/
    DECLARE @TableScript nvarchar(max)
    SELECT @TableScript = 
    '
    CREATE TABLE dbo.Destination(
        bar INT IDENTITY(' + 
                     CAST(ISNULL(MAX(bar),0)+1 AS VARCHAR) + ',1)  PRIMARY KEY,
        filler CHAR(8000),
        filler2 CHAR(49)
        )

        ALTER TABLE dbo.tblFoo SWITCH TO dbo.Destination;
    '       
    FROM dbo.tblFoo
    WITH (TABLOCKX,HOLDLOCK)

    EXEC(@TableScript)


    DROP TABLE dbo.tblFoo;

    EXECUTE sp_rename N'dbo.Destination', N'tblFoo', 'OBJECT';


    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0 ROLLBACK TRANSACTION;
    PRINT ERROR_MESSAGE();
END CATCH;

結果をテストします。

INSERT INTO dbo.tblFoo (filler,filler2) 
OUTPUT inserted.*
VALUES ('foo','bar')

与える

bar         filler    filler2
----------- --------- ---------
10001       foo       bar      

掃除

DROP TABLE dbo.tblFoo
64
Martin Smith

SQL Server:行が含まれるテーブルに自動インクリメントを設定する方法:

この戦略では、行を物理的に2回コピーします。コピーするテーブルが非常に大きい場合、時間がかかることがあります。

データを保存し、自動インクリメントとプライマリキーを使用してテーブルを削除して再構築し、データを再度読み込むことができます。

例で説明します。

ステップ1、テーブルfoobarを作成します(主キーまたは自動インクリメントなし):

CREATE TABLE foobar(
    id int NOT NULL,
    name nchar(100) NOT NULL,
)

ステップ2、いくつかの行を挿入

insert into foobar values(1, 'one');
insert into foobar values(2, 'two');
insert into foobar values(3, 'three');

ステップ3、foobarデータを一時テーブルにコピーします:

select * into temp_foobar from foobar

ステップ4、foobarテーブルの削除:

drop table foobar;

ステップ5、主キーと自動インクリメントのプロパティを使用してテーブルを再作成します:

CREATE TABLE foobar(
    id int primary key IDENTITY(1, 1) NOT NULL,
    name nchar(100) NOT NULL,
)

ステップ6、一時テーブルからデータをfoobarに挿入する

SET IDENTITY_INSERT temp_foobar ON
INSERT into foobar (id, name) select id, name from temp_foobar;

手順7、一時テーブルを削除し、動作するかどうかを確認します:

drop table temp_foobar;
select * from foobar;

これを取得する必要があります。foobarテーブルを調べると、id列は1の自動インクリメントであり、idは主キーです。

1    one
2    two
3    three
4
Eric Leschinski

デザイナーを介してこれを実行する場合は、既存の列をヌル可能に変更するときに「 」「変更の保存は許可されていません」の指示に従って実行できます

3
Daveo

はい、できます。 [ツール]> [デザイナ]> [テーブルとデザイナ]に移動し、「テーブルの再作成を妨げる変更の保存を禁止する」のチェックを外します。

2
Peter Pauletto

新しい列を追加したくなく、現在のint列が一意であることを保証できる場合は、すべてのデータを一時テーブルに選択し、テーブルを削除して、指定されたIDENTITY列で再作成できます。次に、SET IDENTITY INSERT ON一時テーブル内のすべてのデータを新しいテーブルに挿入できます。

2
Duncan Howe

いいえ、データのある既存の列に自動増分オプションを追加することはできません。あなたが言及したオプションが最適だと思います。

ご覧ください here

1
Homam

以下のスクリプトは良い解決策になる可能性があります。また、大規模なデータで作業しました。

NO_WAITを使用したALTER DATABASE WMlive SET RECOVERY SIMPLE

ALTER TABLE WMBOMTABLE DROP CONSTRAINT PK_WMBomTable

ALTER TABLE WMBOMTABLEドロップ列BOMID

ALTER TABLE WMBOMTABLE ADD BomID int IDENTITY(1、1)NOT NULL;

ALTER TABLE WMBOMTABLE ADD CONSTRAINT PK_WMBomTable PRIMARY KEY CLUSTERED(BomID);

ALTER DATABASE WMlive SET RECOVERY FULL WITH NO_WAIT

0
Jatin Dave