Red*_*ter 4 index sql-server constraint primary-key sql-server-2008-r2
我有一张名为MyTable. 主键是一个名为 的标识 int 列MyTableID。在MyTableID名为的 PK 列上有一个唯一的聚集索引PK_MyTable。
我注意到IX_MyTable_MytableID该表上有一个额外的非聚集唯一索引,只有一个 column MyTableID,没有其他包含的列。这个索引显然是多余的,但是当我尝试删除它时,我收到一条错误消息:
The constraint 'IX_MyTable_MyTableID' is being referenced by table 'OtherTable',
foreign key constraint 'FK__OtherTable__MyTableID__369C23FC'.
Run Code Online (Sandbox Code Playgroud)
为什么 FK 约束依赖于非聚集唯一索引而不是主键约束?如何更新 FK 以使用聚集 PK 索引而不是其他索引?
因为外键可以指向主键或唯一约束,并且创建该外键的人可能在主键存在之前创建了它(或者他们将 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));
Run Code Online (Sandbox Code Playgroud)
事实上,这两个外键都将指向在该列 ( )上定义的第一个唯一约束myx。
您可以通过删除并重新创建它来修复另一个表上的外键。您将需要对指向此列的任何其他表重复该过程。您可以轻松找到这些:
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');
Run Code Online (Sandbox Code Playgroud)
结果:
dbo OtherTable1 FK__OtherTable1__ID__32E0915F
dbo OtherTable2 FK__OtherTable2__ID__35BCFE0A
Run Code Online (Sandbox Code Playgroud)
甚至生成一个脚本来删除和重新创建它们(同时删除冗余的唯一约束):
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;
Run Code Online (Sandbox Code Playgroud)
结果:
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);
Run Code Online (Sandbox Code Playgroud)
这明确处理了这种情况,其中约束仅涉及单个列。如果涉及多个列,它会变得更加复杂(并且此答案并非旨在解决该问题)。如果外键指向一个冗余的唯一索引(它具有相同的底层结构,但使用稍微不同的 DDL 创建),我也没有测试这是否完全按照编码工作。为读者练习。:-)
| 归档时间: |
|
| 查看次数: |
6609 次 |
| 最近记录: |