web-dev-qa-db-ja.com

SQL Serverでレコードを削除した後にIDシードをリセットする

SQL Serverデータベーステーブルにレコードを挿入しました。テーブルに主キーが定義されていて、自動インクリメントIDシードが「はい」に設定されています。これは主に、SQL Azureでは各テーブルに主キーとIDを定義する必要があるためです。 

しかし、テーブルからいくつかのレコードを削除しなければならないので、それらのテーブルのアイデンティティシードは乱され、インデックスカラム(1の増分で自動生成される)は乱されるでしょう。

レコードが削除された後にID列をリセットして列が昇順の番号順になるようにするにはどうすればよいですか。

Identityカラムは、データベース内のどこでも外部キーとしては使用されません。

553
Romil N

DBCC CHECKIDENT managementコマンドはIDカウンタをリセットするために使用されます。コマンド構文は次のとおりです。

DBCC CHECKIDENT (table_name [, { NORESEED | { RESEED [, new_reseed_value ]}}])
[ WITH NO_INFOMSGS ]

例: 

DBCC CHECKIDENT ('[TestTable]', RESEED, 0);
GO

Azure SQL Databaseの以前のバージョンではサポートされていませんでしたが、現在はサポートされています。


new_reseed_value引数はSQL Serverのバージョンによって異なります - ドキュメントによれば : 

テーブルに行がある場合は、次の行にnew_reseed_valueという値が挿入されます。 SQL Server 2008 R2以前のバージョンでは、挿入される次の行にnew_reseed_value +現在の増分値が使用されます。

ただし、 この情報は誤解を招く可能性があります (実際には明らかに間違っています)少なくともSQL Server 2012は現在もnew_reseed_value +現在の増分値ロジックを使用していることを示しているマイクロソフトは、同じページにある独自のExample Cと矛盾することさえあります。

C.現在のアイデンティティ値を新しい値に強制する

次の例では、AddressTypeテーブルの AddressTypeID列の現在のID値を強制的に10にします。テーブルには既存の行があるため、挿入される次の行には11 の値、つまり列の値に定義された新しい現在の増分値に1を加えた値。

USE AdventureWorks2012;  
GO  
DBCC CHECKIDENT ('Person.AddressType', RESEED, 10);  
GO

それでも、これはすべて新しいSQL Serverバージョンでは異なる動作のためのオプションを残します。マイクロソフトが独自のドキュメントで整理するまで、使用する前に実際のテストを行うことが唯一の確実な方法です。

920
Petr Abdulin
DBCC CHECKIDENT ('TestTable', RESEED, 0)
GO

0はidentityの開始値です。

188
anil shah

IF all がデータからDELETEを介してテーブルから削除されている(つまり、WHERE句がない)こと、そしてa)許可が許す限りb)FKがないことに注意してください。 TRUNCATE TABLEを使用すると(より効率的なDELETEを使用してIDENTITYシードを同時にリセットするため)テーブルを参照する(ここではそうであると思われる)のが好ましいでしょう。以下の詳細は、 TRUNCATE TABLE のMSDNページから引用されています。

DELETEステートメントと比較して、TRUNCATE TABLEには以下の利点があります。

  • 使用されるトランザクションログスペースが少なくなります。

    DELETEステートメントは、一度に1行ずつ行を削除し、削除された行ごとにエントリをトランザクションログに記録します。 TRUNCATE TABLEは、テーブルデータの格納に使用されているデータページの割り当てを解除することでデータを削除し、ページ割り当て解除のみをトランザクションログに記録します。

  • 通常使用されるロックは少なくなります。

    行ロックを使用してDELETE文を実行すると、テーブル内の各行が削除のためにロックされます。 TRUNCATE TABLEは常にテーブル(スキーマ(SCH-M)ロックを含む)とページをロックしますが、各行はロックしません。

  • 例外なく、ゼロページはテーブルに残ります。

    DELETEステートメントが実行された後、テーブルはまだ空のページを含むことができます。たとえば、ヒープ内の空のページは、少なくとも排他的(LCK_M_X)テーブルロックがないと割り当て解除できません。削除操作がテーブルロックを使用しない場合、テーブル(ヒープ)には空のページが多数含まれます。インデックスの場合、削除操作によって空のページが残ることがありますが、これらのページはバックグラウンドクリーンアッププロセスによって迅速に割り当て解除されます。

テーブルにID列が含まれている場合、その列のカウンターはその列に定義されているシード値にリセットされます。シードが定義されていない場合は、デフォルト値1が使用されます。 IDカウンタを保持するには、代わりにDELETEを使用してください。

だから、以下:

DELETE FROM [MyTable];
DBCC CHECKIDENT ('[MyTable]', RESEED, 0);

ちょうどになります:

TRUNCATE TABLE [MyTable];

制限事項などの追加情報についてはTRUNCATE TABLEのドキュメント(上記リンク)をご覧ください。

71
Solomon Rutzky

ほとんどの回答はRESEEDを0にすることを示唆していますが、利用可能な次のIdに再シードするだけでよい

declare @max int
select @max=max([Id])from [TestTable]
if @max IS NULL   //check when max is returned as null
  SET @max = 0
DBCC CHECKIDENT ('[TestTable]', RESEED,@max)

これによりテーブルがチェックされ、次のIDにリセットされます。

62
Atal Kishore

私は@anil shahs答えを試みました、そしてそれはアイデンティティをリセットしました。しかし、新しい行が挿入されたとき、それはidentity = 2を取得しました。その代わりに、構文を次のように変更しました。

DELETE FROM [TestTable]

DBCC CHECKIDENT ('[TestTable]', RESEED, 0)
GO

その後、最初の行はidentity = 1になります。

57
Mikael Engver

ほとんどの回答はRESEEDから0を提案していますが、これをTRUNCATEDテーブルの欠陥と見なしている人もいますが、MicrosoftはIDを除外する解決策を持っています

DBCC CHECKIDENT ('[TestTable]', RESEED)

これによりテーブルがチェックされ、次のIDにリセットされます。これはMS SQL 2005から現在まで利用可能です。

https://msdn.Microsoft.com/ja-jp/library/ms176057.aspx

15
SollyM

@jacob

DBCC CHECKIDENT ('[TestTable]', RESEED,0)
DBCC CHECKIDENT ('[TestTable]', RESEED)

私のために働きました、私はちょうどテーブルから最初にすべてのエントリーをクリアしなければなりませんでした、そして次に削除の後にトリガーポイントで上記を加えました。今私はエントリを削除するたびにそこから取得されます。

5
epic

ID列を新しいIDでリセットします...

DECLARE @MAX INT
SELECT @MAX=ISNULL(MAX(Id),0) FROM [TestTable]

DBCC CHECKIDENT ('[TestTable]', RESEED,@MAX)
4
Mukesh Pandey

2コマンドを発行するとトリックを行うことができます

DBCC CHECKIDENT ('[TestTable]', RESEED,0)
DBCC CHECKIDENT ('[TestTable]', RESEED)

最初のものはアイデンティティをゼロにリセットし、次のものは次の利用可能な値に設定します

4
jacob

これはよくある質問であり、答えは常に同じです。それをしないでください。アイデンティティ値は任意のものとして扱われるべきであり、「正しい」順序はありません。

4
Ben Thul

Truncateテーブルは、レコードをクリアし、カウンターをリセットし、そしてディススペースを取り戻すので、好ましいです。 

DeleteおよびCheckIdentは、外部キーによって切り捨てられない場合にのみ使用してください。

3
Dyna Dave

このスクリプトを実行してID列をリセットします。 2つの変更を加える必要があります。 tableXYZを更新する必要のあるテーブルに置き換えます。また、ID列の名前を一時テーブルから削除する必要があります。これは、35,000行3列のテーブルでは瞬間的でした。明らかに、テーブルをバックアップして、まずテスト環境でこれを試してください。 


select * 
into #temp
From tableXYZ

set identity_insert tableXYZ ON

truncate table tableXYZ

alter table #temp drop column (nameOfIdentityColumn)

set identity_insert tableXYZ OFF

insert into tableXYZ
select * from #temp
2
Matthew Baic

このストアドプロシージャを使用してください。

IF (object_id('[dbo].[pResetIdentityField]') IS NULL)
  BEGIN
    EXEC('CREATE PROCEDURE [dbo].[pResetIdentityField] AS SELECT 1 FROM DUMMY');
  END
GO

SET  ANSI_NULLS ON
GO
SET  QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[pResetIdentityField]
  @pSchemaName NVARCHAR(1000)
, @pTableName NVARCHAR(1000) AS
DECLARE @max   INT;
DECLARE @fullTableName   NVARCHAR(2000) = @pSchemaName + '.' + @pTableName;

DECLARE @identityColumn   NVARCHAR(1000);

SELECT @identityColumn = c.[name]
FROM sys.tables t
     INNER JOIN sys.schemas s ON t.[schema_id] = s.[schema_id]
     INNER JOIN sys.columns c ON c.[object_id] = t.[object_id]
WHERE     c.is_identity = 1
      AND t.name = @pTableName
      AND s.[name] = @pSchemaName

IF @identityColumn IS NULL
  BEGIN
    RAISERROR(
      'One of the following is true: 1. the table you specified doesn''t have an identity field, 2. you specified an invalid schema, 3. you specified an invalid table'
    , 16
    , 1);
    RETURN;
  END;

DECLARE @sqlString   NVARCHAR(MAX) = N'SELECT @maxOut = max(' + @identityColumn + ') FROM ' + @fullTableName;

EXECUTE sp_executesql @stmt = @sqlString, @params = N'@maxOut int OUTPUT', @maxOut = @max OUTPUT

IF @max IS NULL
  SET @max = 0

print(@max)

DBCC CHECKIDENT (@fullTableName, RESEED, @max)
go

--exec pResetIdentityField 'dbo', 'Table'

私の答えをもう一度見てください。私はあなたが知っておくべきであることをSQL Server 2008 R2で奇妙な行動に遭遇しました。

drop table test01

create table test01 (Id int identity(1,1), descr nvarchar(10))

execute pResetIdentityField 'dbo', 'test01'

insert into test01 (descr) values('Item 1')

select * from test01

delete from test01

execute pResetIdentityField 'dbo', 'test01'

insert into test01 (descr) values('Item 1')

select * from test01

最初の選択は0, Item 1を生成します。

2番目のものは1, Item 1を生成します。テーブルが作成された直後にリセットを実行すると、次の値は0になります。正直なところ、Microsoftがこれを正しく行えないのは当然のことです。これは、テーブルを再作成した後や、テーブルがすでに作成されているときに実行することがある参照テーブルを作成するスクリプトファイルがあるためです。

1
costa

テーブル全体をクリーンアップしない限り、0に再シードすることはあまり実用的ではありません。

そうでなければ、アンソニー・レイモンドの答えは完璧です。 ID列の最大値を最初に取得してから、最大値をシードします。

0
Ali Sufyan

完全なDELETE行とIDENTITYカウントをリセットするには、これを使用します(SQL Server 2008 R2)。

USE mydb

-- ##################################################################################################################
-- DANGEROUS!!!! USE WITH CARE
-- ##################################################################################################################

DECLARE
  db_cursor CURSOR FOR
    SELECT TABLE_NAME
      FROM INFORMATION_SCHEMA.TABLES
     WHERE TABLE_TYPE = 'BASE TABLE'
       AND TABLE_CATALOG = 'mydb'

DECLARE @tblname VARCHAR(50)
SET @tblname = ''

OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @tblname

WHILE @@FETCH_STATUS = 0
BEGIN
  IF CHARINDEX('mycommonwordforalltablesIwanttodothisto', @tblname) > 0
    BEGIN
      EXEC('DELETE FROM ' + @tblname)
      DBCC CHECKIDENT (@tblname, RESEED, 0)
    END

  FETCH NEXT FROM db_cursor INTO @tblname
END

CLOSE db_cursor
DEALLOCATE db_cursor
GO
0
Fandango68

これを行うには、次のスクリプトを使用します。テーブルからすべての行を削除し、現在IDENT_CURRENTが1に設定されている場合、つまり最初はテーブルに1行しかない場合、 "エラー"が発生するシナリオは1つだけです。

DECLARE @maxID int = (SELECT MAX(ID) FROM dbo.Tbl)
;

IF @maxID IS NULL
    IF (SELECT IDENT_CURRENT('dbo.Tbl')) > 1
        DBCC CHECKIDENT ('dbo.Tbl', RESEED, 0)
    ELSE
        DBCC CHECKIDENT ('dbo.Tbl', RESEED, 1)
    ;
ELSE
    DBCC CHECKIDENT ('dbo.Tbl', RESEED, @maxID)
;
0
Chris Mack
DBCC CHECKIDENT (<TableName>, reseed, 0)

これにより、現在の識別値が0に設定されます。

次の値を挿入すると、identity値は1に増加します。

0
Bimzee