テーブルの主キーを ID 列に変更する必要がありますが、テーブルには既に多数の行があります。
ID をクリーンアップして ID が 1 から連続していることを確認するスクリプトがあり、テスト データベースで正常に動作します。
ID プロパティを持つように列を変更する SQL コマンドは何ですか?
テーブルの主キーを ID 列に変更する必要がありますが、テーブルには既に多数の行があります。
ID をクリーンアップして ID が 1 から連続していることを確認するスクリプトがあり、テスト データベースで正常に動作します。
ID プロパティを持つように列を変更する SQL コマンドは何ですか?
ID の既存の列を変更することはできません。
2 つのオプションがあります。
ID を使用して新しいテーブルを作成し、既存のテーブルを削除します
ID を使用して新しい列を作成し、既存の列をドロップします
アプローチ 1. (新しいテーブル) ここでは、新しく作成された ID 列の既存のデータ値を保持できます。「存在しない場合」が満たされない場合、すべてのデータが失われることに注意してください。そのため、必ずドロップにも条件を付けてください。
CREATE TABLE dbo.Tmp_Names
(
Id int NOT NULL
IDENTITY(1, 1),
Name varchar(50) NULL
)
ON [PRIMARY]
go
SET IDENTITY_INSERT dbo.Tmp_Names ON
go
IF EXISTS ( SELECT *
FROM dbo.Names )
INSERT INTO dbo.Tmp_Names ( Id, Name )
SELECT Id,
Name
FROM dbo.Names TABLOCKX
go
SET IDENTITY_INSERT dbo.Tmp_Names OFF
go
DROP TABLE dbo.Names
go
Exec sp_rename 'Tmp_Names', 'Names'
アプローチ 2 (新しい列) 新しく作成された ID 列に既存のデータ値を保持することはできません。ID 列には一連の番号が保持されます。
Alter Table Names
Add Id_new Int Identity(1, 1)
Go
Alter Table Names Drop Column ID
Go
Exec sp_rename 'Names.Id_new', 'ID', 'Column'
詳細については、次の Microsoft SQL Server フォーラムの投稿を参照してください。
SQL 2005 以降では、テーブルのデータ ページを変更せずにこの問題を解決する方法があります。これは、すべてのデータ ページにアクセスするのに数分から数時間かかる可能性がある大規模なテーブルでは重要です。このトリックは、ID 列が主キーである場合、クラスター化または非クラスター化インデックスの一部である場合、または単純な "列の追加/削除/名前変更" ソリューションを失敗させる可能性があるその他の問題がある場合でも機能します。
秘訣は次のとおりです。SQL Server のALTER TABLE...SWITCHステートメントを使用して、データを変更せずにテーブルのスキーマを変更できます。つまり、IDENTITY 列を使用せずに、同一のテーブル スキーマを持つ IDENTITY でテーブルを置き換えることができます。同じトリックが IDENTITY を既存の列に追加するために機能します。
通常、ALTER TABLE...SWITCHは、パーティション テーブル内のフル パーティションを新しい空のパーティションに効率的に置き換えるために使用されます。ただし、パーティション化されていないテーブルでも使用できます。
このトリックを使用して、5 秒以内に、25 億行のテーブルの列を IDENTITY から非 IDENTITY に変換しました (クエリ プランが非 IDENTITY でより適切に機能する複数時間のクエリを実行するため)。列)、IDENTITY 設定を再び 5 秒以内に復元しました。
これがどのように機能するかのコードサンプルです。
CREATE TABLE Test
(
id int identity(1,1),
somecolumn varchar(10)
);
INSERT INTO Test VALUES ('Hello');
INSERT INTO Test VALUES ('World');
-- copy the table. use same schema, but no identity
CREATE TABLE Test2
(
id int NOT NULL,
somecolumn varchar(10)
);
ALTER TABLE Test SWITCH TO Test2;
-- drop the original (now empty) table
DROP TABLE Test;
-- rename new table to old table's name
EXEC sp_rename 'Test2','Test';
-- update the identity seed
DBCC CHECKIDENT('Test');
-- see same records
SELECT * FROM Test;
これは明らかに他の回答のソリューションよりも複雑ですが、テーブルが大きい場合、これは実際の命の恩人になる可能性があります. いくつかの注意事項があります:
上記の要件を詳述した TechNetの優れた記事があります。
更新 - Eric Wuは、このソリューションに関する重要な情報を追加する以下のコメントを持っていました。ここにコピーして、より注目を集めるようにします。
ここで、言及する価値のある別の警告があります。新しいテーブルは古いテーブルからデータを問題なく受け取り、すべての新しい行は ID パターンに従って挿入されますが、列が主キーの場合は 1 から始まり、破損する可能性があります。
DBCC CHECKIDENT('<newTableName>')
切り替え直後の実行を検討してください。詳細については、 msdn.microsoft.com/en-us/library/ms176057.aspxを参照してください。
テーブルが新しい行でアクティブに拡張されている場合 (IDENTITY の追加と新しい行の追加の間にダウンタイムがほとんどないことを意味しますDBCC CHECKIDENT
)、新しいテーブル スキーマの ID シード値を手動で設定する代わりに、テーブル内の既存の最大 ID よりも大きい、たとえば.と のIDENTITY (2435457, 1)
両方をトランザクションに含めることができるかもしれません(または、テストしていません) が、シード値を手動で設定する方が簡単で安全なようです。ALTER TABLE...SWITCH
DBCC CHECKIDENT
明らかに、新しい行がテーブルに追加されていない場合 (または、毎日の ETL プロセスのようにたまにしか追加されない場合)、この競合状態は発生しないのでDBCC CHECKIDENT
問題ありません。
列をIDENTITY列に変更することはできません。最初からIDENTITYとして定義されている新しい列を作成し、古い列を削除して、新しい列の名前を古い名前に変更する必要があります。
ALTER TABLE (yourTable) ADD NewColumn INT IDENTITY(1,1)
ALTER TABLE (yourTable) DROP COLUMN OldColumnName
EXEC sp_rename 'yourTable.NewColumn', 'OldColumnName', 'COLUMN'
マーク
ここで説明されているクールなソリューションがあります: SQL SERVER – 列の ID プロパティの追加または削除
SQLマネージャーでテーブルを手動で編集し、IDを切り替え、変更を保存しないでください。変更のために作成されるスクリプトを表示し、コピーして後で使用します。
スクリプトには、変更するテーブルに関連するすべての外部キー、インデックスなどが含まれているため、時間を大幅に節約できます。これを手動で書くことは... 神は禁じます。
IDENTITY の代わりに SEQUENCEを使用することを検討してください。
IN sql server 2014 (下位バージョンについてはわかりません) シーケンスを使用して、これを簡単に行うことができます。
CREATE SEQUENCE sequence_name START WITH here_higher_number_than_max_existed_value_in_column INCREMENT BY 1;
ALTER TABLE table_name ADD CONSTRAINT constraint_name DEFAULT NEXT VALUE FOR sequence_name FOR column_name
ここから:列のデフォルト値としてのシーケンス
簡単な説明
sp_RENAME を使用して既存の列の名前を変更します。
EXEC sp_RENAME 'Table_Name.Existing_ColumnName' , 'New_ColumnName', 'COLUMN'
名前の変更の例:
既存の列 UserID の名前が OldUserID に変更されました
EXEC sp_RENAME 'AdminUsers.UserID' , 'OldUserID', 'COLUMN'
次に、alter query を使用して新しい列を追加し、主キーと ID 値として設定します
ALTER TABLE TableName ADD Old_ColumnName INT NOT NULL PRIMARY KEY IDENTITY(1,1)
主キーの設定の例
新しく作成された列名は UserID です
ALTER TABLE Users ADD UserID INT NOT NULL PRIMARY KEY IDENTITY(1,1)
次に、名前を変更した列をドロップします
ALTER TABLE Table_Name DROP COLUMN Renamed_ColumnName
名前を変更した列をドロップする例
ALTER TABLE Users DROP COLUMN OldUserID
これで、主キーと ID がテーブルの既存の列に追加されました。
私はたまたま DBA のいないチームに参加した Java 開発者であり、開発者として DBA の権利を取得できません。私は 2 つのデータベース間でスキーマ全体を移動する任務を負っていたので、DBA を持たずにスクリプトを実行して移動する必要がありました。管理者権限がなかったため、SQL Server 2008 で GUI を使用できませんでした。
すべてが問題なく移動されましたが、新しい schema.table でストアド プロシージャを実行すると、テーブルの ID フィールドが失われていることがわかりました。テーブルを作成したスクリプトを再確認したところ、そこにありましたが、スクリプトを実行したときに SQL Server はそれを取得しませんでした。後で DBA から、同じ問題を以前に見たことがあると言われました。
いずれにせよ、SQL Server 2008 の場合、これらは私がこれを解決するために行った手順であり、機能したので、誰かの助けになることを期待してここに投稿しています。これは、別のテーブルに FK 依存関係があり、これがより困難になったため、私が行ったことです。
このクエリを使用して、ID が実際に欠落していることを確認し、テーブルの依存関係を表示しました。
1.) テーブルの統計を検索します。
exec sp_help 'dbo.table_name_old';
2.) 以前の PK フィールドに ID フィールドを追加することを除いて、重複する同一の新しいテーブルを作成します。
3.) ID を無効にしてデータを移動します。
SET IDENTITY_INSERT dbo.table_name ON
4.) データを転送します。
INSERT INTO dbo.table_name_new
(
field1, field2, etc...
)
SELECT
field1, field2, etc...
FROM
dbo.table_name_old;
5.) データが存在することを確認します。
SELECT * FROM dbo.table_name_new
6.) ID を再度有効にします。
SET IDENTITY_INSERT ToyRecP.ToyAwards.lkpFile_New OFF
7.)これは、すべての FK リレーションシップを取得して、元のテーブルがどのテーブルを依存関係として参照しているかを確認するのに最適なスクリプトであり、多くのテーブルに出くわしたので、キーパーです!
SELECT f.name AS ForeignKey,
OBJECT_NAME(f.parent_object_id) AS TableName,
COL_NAME(fc.parent_object_id, fc.parent_column_id) AS ColumnName,
OBJECT_NAME (f.referenced_object_id) AS ReferenceTableName,
COL_NAME(fc.referenced_object_id, fc.referenced_column_id) AS ReferenceColumnName
FROM sys.foreign_keys AS f
INNER JOIN sys.foreign_key_columns AS fc
ON f.OBJECT_ID = fc.constraint_object_id
ORDER BY ReferenceTableName;
8.) この次のステップの前に、関連するすべてのテーブルのすべての PK および FK スクリプトがあることを確認してください。
9.) 各キーを右クリックして、SQL Server 2008 を使用してこれをスクリプト化できます。
10.) 次の構文を使用して、依存関係テーブルから FK を削除します。
ALTER TABLE [dbo].[table_name] DROP CONSTRAINT [Name_of_FK]
11.) 元のテーブルを削除します。
DROP TABLE dbo.table_name_old;
13.) これらの次の手順は、手順 9 で SQL Server 2008 で作成したスクリプトに依存しています。
--PK を新しいテーブルに追加します。
-- FK を新しいテーブルに追加します。
-- FK を依存関係テーブルに追加します。
14.) すべてが正しく、完全であることを確認します。GUI を使用してテーブルを確認しました。
15.) 新しいテーブルの名前を元のテーブル名に変更します。
exec sp_RENAME '[Schema_Name.OldTableName]' , '[NewTableName]';
最後に、すべてがうまくいきました!
通常のケースで理解しているように、Identity プロパティを持つ主キーを持つテーブルを作成している
ため、制約ルールが列構造を検証しているため、主キー制約に関連付けられている列の名前を変更または削除することはできません。
これを実現するには、次の方法でいくつかの手順を処理する必要があります: TableName = 'Employee'およびColumnName = ' EmployeeId' と
仮定し
ます 1. 'Employee' テーブルに新しい列 'EmployeeId_new' を追加します
ALTER TABLE Employee ADD EmployeeId_new INT IDENTITY( 1,1)
「Employee」テーブルから列「EmployeeId」を削除します
ALTER TABLE Employee DROP COLUMN EmployeeId
これは、主キー制約ルールが適用され、列構造を検証しているため、エラーをスローします。
*### 'メッセージ 5074、レベル 16、状態 1、行 1 オブジェクト [PK_dbo.Employee] は列 [EmployeeId] に依存しています。' ###
したがって、最初にテーブル「Employee」から主キー制約を削除する必要があり、次に列
ALTER TABLE Employee DROP 制約 [PK_dbo.Employee]を削除できます。
これで、 ALTER TABLE Employee DROP COLUMN EmployeeIdエラーが発生した前の手順で行ったように、「Employee」テーブルから列「EmployeeId」を削除できます。
列 'EmployeeId' がテーブルから削除されたので、新しく追加された新しい列 'EmployeeId_new' の名前を 'EmployeeId' に
変更し
ます sp_rename 'Employee.EmployeeId', 'EmployeeId_new', 'COLUMN'
以前と同じ形式でテーブルを再配置するには、列 'EmployeeId' に主キー制約を追加する必要があります
ALTER TABLE Employee 制約を追加 [PK_dbo.Employee] 主キー (EmployeeId)
8. 'EmployeeId' を持つテーブル 'Employee' が、既存の主キー制約と共に ID ルール用に変更されました。
そのようにすることはできません。別の列を追加し、元の列を削除して新しい列の名前を変更するか、新しいテーブルを作成し、データをコピーして古いテーブルを削除してから、新しいテーブルの名前を古いテーブルに変更する必要がありますテーブル
SSMS を使用し、デザイナーで ID プロパティを ON に設定した場合、SQL Server はバックグラウンドで次のことを行います。[user] という名前のテーブルがある場合、UserID と ID を作成すると、次のようになります。
BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
GO
CREATE TABLE dbo.Tmp_User
(
UserID int NOT NULL IDENTITY (1, 1),
LastName varchar(50) NOT NULL,
FirstName varchar(50) NOT NULL,
MiddleInitial char(1) NULL
) ON [PRIMARY]
GO
SET IDENTITY_INSERT dbo.Tmp_User ON
GO
IF EXISTS(SELECT * FROM dbo.[User])
EXEC('INSERT INTO dbo.Tmp_User (UserID, LastName, FirstName, MiddleInitial)
SELECT UserID, LastName, FirstName, MiddleInitialFROM dbo.[User] TABLOCKX')
GO
SET IDENTITY_INSERT dbo.Tmp_User OFF
GO
GO
DROP TABLE dbo.[User]
GO
EXECUTE sp_rename N'dbo.Tmp_User', N'User', 'OBJECT'
GO
ALTER TABLE dbo.[User] ADD CONSTRAINT
PK_User PRIMARY KEY CLUSTERED
(
UserID
) ON [PRIMARY]
GO
COMMIT
ビットごとの値を設定することでシステムテーブルをハックしてそれを達成する方法があると言ったが、それはサポートされておらず、私はそれをしないだろう
設計上、既存の列の ID 機能をオンまたはオフにする簡単な方法はありません。これを行う唯一のクリーンな方法は、新しい列を作成して ID 列にするか、新しいテーブルを作成してデータを移行することです。
SQL Server Management Studio を使用して列 "id" の ID 値を削除すると、新しい一時テーブルが作成され、データが一時テーブルに移動され、古いテーブルが削除され、新しいテーブルの名前が変更されます。
Management Studio を使用して変更を行い、デザイナーで右クリックして [変更スクリプトの生成] を選択します。
これが、SQL サーバーがバックグラウンドで行っていることであることがわかります。
悲しいことに、それはありません。IDENTITY プロパティは、列ではなくテーブルに属します。
簡単な方法は GUI で行うことですが、これができない場合は、データをコピーし、列を削除し、ID を付けて再度追加し、データを元に戻すという長い道のりをたどることができます。
一撃のアカウントはこちらをご覧ください。
元の投稿者が実際に既存の列をテーブルの に設定することを望んでいてPRIMARY KEY
、実際には列を列にする必要がなかった場合IDENTITY
(2 つの異なること)、これは t-SQL を介して次のように行うことができます。
ALTER TABLE [YourTableName]
ADD CONSTRAINT [ColumnToSetAsPrimaryKey] PRIMARY KEY ([ColumnToSetAsPrimaryKey])
PRIMARY KEY
オプションの後の列名を囲む括弧に注意してください。
この投稿は古いものであり、リクエスターのニーズについて推測していますが、この追加情報は、このスレッドに遭遇したユーザーにとって役立つと感じました。この会話により、既存の列を最初に新しい列として追加せずに主キーを作成すると、正しくありません。
tsql を使用して既存の列を ID 列に変更できるとは思えません。ただし、Enterprise Manager のデザイン ビューを使用して行うことができます。
または、ID 列として新しい行を作成し、古い列を削除してから、新しい列の名前を変更することもできます。
ALTER TABLE FooTable
ADD BarColumn INT IDENTITY(1, 1)
NOT NULL
PRIMARY KEY CLUSTERED
ID セットを持たない主キー = bigint を持つすべてのテーブルのスクリプトを生成します。これにより、生成されたスクリプトと各テーブルのリストが返されます。
SET NOCOUNT ON;
declare @sql table(s varchar(max), id int identity)
DECLARE @table_name nvarchar(max),
@table_schema nvarchar(max);
DECLARE vendor_cursor CURSOR FOR
SELECT
t.name, s.name
FROM sys.schemas AS s
INNER JOIN sys.tables AS t
ON s.[schema_id] = t.[schema_id]
WHERE EXISTS (
SELECT
[c].[name]
from sys.columns [c]
join sys.types [y] on [y].system_type_id = [c].system_type_id
where [c].[object_id] = [t].[object_id] and [y].name = 'bigint' and [c].[column_id] = 1
) and NOT EXISTS
(
SELECT 1 FROM sys.identity_columns
WHERE [object_id] = t.[object_id]
) and exists (
select 1 from sys.indexes as [i]
inner join sys.index_columns as [ic] ON i.OBJECT_ID = ic.OBJECT_ID AND i.index_id = ic.index_id
where object_name([ic].[object_id]) = [t].[name]
)
OPEN vendor_cursor
FETCH NEXT FROM vendor_cursor
INTO @table_name, @table_schema
WHILE @@FETCH_STATUS = 0
BEGIN
DELETE FROM @sql
declare @pkname varchar(100),
@pkcol nvarchar(100)
SELECT top 1
@pkname = i.name,
@pkcol = COL_NAME(ic.OBJECT_ID,ic.column_id)
FROM sys.indexes AS [i]
INNER JOIN sys.index_columns AS [ic] ON i.OBJECT_ID = ic.OBJECT_ID AND i.index_id = ic.index_id
WHERE i.is_primary_key = 1 and OBJECT_NAME(ic.OBJECT_ID) = @table_name
declare @q nvarchar(max) = 'SELECT '+@pkcol+' FROM ['+@table_schema+'].['+@table_name+'] ORDER BY '+@pkcol+' DESC'
DECLARE @ident_seed nvarchar(max) -- Change this to the datatype that you are after
SET @q = REPLACE(@q, 'SELECT', 'SELECT TOP 1 @output = ')
EXEC sp_executeSql @q, N'@output bigint OUTPUT', @ident_seed OUTPUT
insert into @sql(s) values ('BEGIN TRANSACTION')
insert into @sql(s) values ('BEGIN TRY')
-- create statement
insert into @sql(s) values ('create table ['+@table_schema+'].[' + @table_name + '_Temp] (')
-- column list
insert into @sql(s)
select
' ['+[c].[name]+'] ' +
y.name +
(case when [y].[name] like '%varchar' then
coalesce('('+(case when ([c].[max_length] < 0 or [c].[max_length] >= 1024) then 'max' else cast([c].max_length as varchar) end)+')','')
else '' end)
+ ' ' +
case when [c].name = @pkcol then 'IDENTITY(' +COALESCE(@ident_seed, '1')+',1)' else '' end + ' ' +
( case when c.is_nullable = 0 then 'NOT ' else '' end ) + 'NULL ' +
coalesce('DEFAULT ('+(
REPLACE(
REPLACE(
LTrim(
RTrim(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
LTrim(
RTrim(
REPLACE(
REPLACE(
object_definition([c].default_object_id)
,' ','~')
,')',' ')
)
)
,' ','*')
,'~',' ')
,' ','~')
,'(',' ')
)
)
,' ','*')
,'~',' ')
) +
case when object_definition([c].default_object_id) like '%get%date%' then '()' else '' end
+
')','') + ','
from sys.columns c
JOIN sys.types y ON y.system_type_id = c.system_type_id
where OBJECT_NAME(c.[object_id]) = @table_name and [y].name != 'sysname'
order by [c].column_id
update @sql set s=left(s,len(s)-1) where id=@@identity
-- closing bracket
insert into @sql(s) values( ')' )
insert into @sql(s) values( 'SET IDENTITY_INSERT ['+@table_schema+'].['+@table_name+'_Temp] ON')
declare @cols nvarchar(max)
SELECT @cols = STUFF(
(
select ',['+c.name+']'
from sys.columns c
JOIN sys.types y ON y.system_type_id = c.system_type_id
where c.[object_id] = OBJECT_ID(@table_name)
and [y].name != 'sysname'
and [y].name != 'timestamp'
order by [c].column_id
FOR XML PATH ('')
)
, 1, 1, '')
insert into @sql(s) values( 'IF EXISTS(SELECT * FROM ['+@table_schema+'].['+@table_name+'])')
insert into @sql(s) values( 'EXEC(''INSERT INTO ['+@table_schema+'].['+@table_name+'_Temp] ('+@cols+')')
insert into @sql(s) values( 'SELECT '+@cols+' FROM ['+@table_schema+'].['+@table_name+']'')')
insert into @sql(s) values( 'SET IDENTITY_INSERT ['+@table_schema+'].['+@table_name+'_Temp] OFF')
insert into @sql(s) values( 'DROP TABLE ['+@table_schema+'].['+@table_name+']')
insert into @sql(s) values( 'EXECUTE sp_rename N''['+@table_schema+'].['+@table_name+'_Temp]'', N'''+@table_name+''', ''OBJECT''')
if ( @pkname is not null ) begin
insert into @sql(s) values('ALTER TABLE ['+@table_schema+'].['+@table_name+'] ADD CONSTRAINT ['+@pkname+'] PRIMARY KEY CLUSTERED (')
insert into @sql(s)
select ' ['+COLUMN_NAME+'] ASC,' from information_schema.key_column_usage
where constraint_name = @pkname
GROUP BY COLUMN_NAME, ordinal_position
order by ordinal_position
-- remove trailing comma
update @sql set s=left(s,len(s)-1) where id=@@identity
insert into @sql(s) values (' )')
end
insert into @sql(s) values ('--Run your Statements')
insert into @sql(s) values ('COMMIT TRANSACTION')
insert into @sql(s) values ('END TRY')
insert into @sql(s) values ('BEGIN CATCH')
insert into @sql(s) values (' ROLLBACK TRANSACTION')
insert into @sql(s) values (' DECLARE @Msg NVARCHAR(MAX) ')
insert into @sql(s) values (' SELECT @Msg=ERROR_MESSAGE() ')
insert into @sql(s) values (' RAISERROR(''Error Occured: %s'', 20, 101,@msg) WITH LOG')
insert into @sql(s) values ('END CATCH')
declare @fqry nvarchar(max)
-- result!
SELECT @fqry = (select char(10) + s from @sql order by id FOR XML PATH (''))
SELECT @table_name as [Table_Name], @fqry as [Generated_Query]
PRINT 'Table: '+@table_name
EXEC sp_executeSql @fqry
FETCH NEXT FROM vendor_cursor
INTO @table_name, @table_schema
END
CLOSE vendor_cursor;
DEALLOCATE vendor_cursor;