MyTable
という名前のテーブルがあります。主キーは、MyTableID
という名前のidentity int列です。 PK列MyTableID
には、PK_MyTable
という一意のクラスター化インデックスがあります。
単一の列MyTableID
があり、他に含まれている列がない、そのテーブルに追加の非クラスター化一意インデックスIX_MyTable_MytableID
があることに気付きました。このインデックスは明らかに冗長ですが、削除しようとするとエラーメッセージが表示されます。
The constraint 'IX_MyTable_MyTableID' is being referenced by table 'OtherTable',
foreign key constraint 'FK__OtherTable__MyTableID__369C23FC'.
FK制約が主キー制約の代わりに非クラスター化一意インデックスに依存しているのはなぜですか?他のインデックスの代わりにクラスター化PKインデックスを使用するようにFKを更新するにはどうすればよいですか?
外部キーは主キーを指すことができるためor一意の制約であり、その外部キーを作成した人は主キーが存在する前にそれを作成した可能性があります(またはFKをシフトして一意のインデックスを指すようにします)主キーについて何か他のものを変更した)。これは簡単に再現できます。
CREATE TABLE dbo.MyTable(MyTableID INT NOT NULL, CONSTRAINT myx UNIQUE(MyTableID));
CREATE TABLE dbo.OtherTable1(ID INT FOREIGN KEY REFERENCES dbo.MyTable(MyTableID));
ALTER TABLE dbo.MyTable ADD CONSTRAINT PKmyx PRIMARY KEY(MyTableID);
CREATE TABLE dbo.OtherTable2(ID INT FOREIGN KEY REFERENCES dbo.MyTable(MyTableID));
実際、これらの外部キーのbothは、その列(myx
)に定義されたfirst一意制約を指します。
他のテーブルの外部キーを削除して再作成することで修正できます。この列を指す他のテーブルについても、このプロセスを繰り返す必要があります。これらは簡単に見つけることができます:
SELECT s.name,t.name,fk.name
FROM sys.foreign_key_columns AS fkc
INNER JOIN sys.foreign_keys AS fk
ON fkc.constraint_object_id = fk.[object_id]
INNER JOIN sys.tables AS t
ON fkc.parent_object_id = t.[object_id]
INNER JOIN sys.schemas AS s
ON t.[schema_id] = s.[schema_id]
INNER JOIN sys.columns AS c1
ON c1.[object_id] = fkc.referenced_object_id
AND c1.column_id = fkc.referenced_column_id
AND c1.name = N'MyTableID'
WHERE fkc.referenced_object_id = OBJECT_ID('dbo.MyTable');
結果:
dbo OtherTable1 FK__OtherTable1__ID__32E0915F
dbo OtherTable2 FK__OtherTable2__ID__35BCFE0A
そして、それらを削除して再作成するためのスクリプトを生成します(その間、冗長な一意制約を削除します)。
DECLARE
@sql1 NVARCHAR(MAX) = N'',
@sql2 NVARCHAR(MAX) = N'ALTER TABLE dbo.MyTable DROP CONSTRAINT myx;',
@sql3 NVARCHAR(MAX) = N'';
SELECT
@sql1 += N'
ALTER TABLE ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name)
+ ' DROP CONSTRAINT ' + QUOTENAME(fk.name) + ';',
@sql3 += N'
ALTER TABLE ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name)
+ ' ADD CONSTRAINT ' + QUOTENAME(fk.name) + ' FOREIGN KEY '
+ '(' + QUOTENAME(c2.name) + ') REFERENCES dbo.MyTable(MyTableID);'
FROM sys.foreign_key_columns AS fkc
INNER JOIN sys.foreign_keys AS fk
ON fkc.constraint_object_id = fk.[object_id]
INNER JOIN sys.tables AS t
ON fkc.parent_object_id = t.[object_id]
INNER JOIN sys.schemas AS s
ON t.[schema_id] = s.[schema_id]
INNER JOIN sys.columns AS c1
ON c1.[object_id] = fkc.referenced_object_id
AND c1.column_id = fkc.referenced_column_id
AND c1.name = N'MyTableID'
INNER JOIN sys.columns AS c2
ON c2.[object_id] = fkc.parent_object_id
AND c2.column_id = fkc.parent_column_id
WHERE fkc.referenced_object_id = OBJECT_ID('dbo.MyTable');
PRINT @sql1;
PRINT @sql2;
PRINT @sql3;
-- EXEC sp_executesql @sql1;
-- EXEC sp_executesql @sql2;
-- EXEC sp_executesql @sql3;
結果:
ALTER TABLE [dbo].[OtherTable1] DROP CONSTRAINT [FK__OtherTable1__ID__32E0915F];
ALTER TABLE [dbo].[OtherTable2] DROP CONSTRAINT [FK__OtherTable2__ID__35BCFE0A];
ALTER TABLE dbo.MyTable DROP CONSTRAINT myx;
ALTER TABLE [dbo].[OtherTable1] ADD CONSTRAINT [FK__OtherTable1__ID__32E0915F]
FOREIGN KEY ([ID]) REFERENCES dbo.MyTable(MyTableID);
ALTER TABLE [dbo].[OtherTable2] ADD CONSTRAINT [FK__OtherTable2__ID__35BCFE0A]
FOREIGN KEY ([ID]) REFERENCES dbo.MyTable(MyTableID);
これは、このケースを明示的に処理します。この場合、制約には単一の列のみが含まれます。複数の列が関係している場合は少し複雑になります(この回答はその問題を解決するためのものではありません)。また、外部キーが冗長な一意のインデックス(基本的な構造は同じですが、わずかに異なるDDLで作成されている)を指している場合、これがコーディングどおりに機能するかどうかもテストしませんでした。読者のための練習。 :-)