Primary-Key

如何更改 SQL Azure 上的現有主鍵?

  • July 22, 2015

我想修改 SQL Azure 表上的現有主鍵。

它目前有一列,我想添加另一列。

現在,在 SQL Server 2008 上,這是小菜一碟,只是在 SSMS 中做到了,噗。完畢。如果我從 SQL Server 編寫腳本,這就是 PK 的樣子:

ALTER TABLE [dbo].[Friend] ADD  CONSTRAINT [PK_Friend] PRIMARY KEY CLUSTERED 
(
 [UserId] ASC,
 [Id] ASC
)

但是,在 SQL Azure 上,當我嘗試執行上述操作時,它當然會失敗:

Table 'Friend' already has a primary key defined on it.

好的,所以我嘗試刪除密鑰:

Tables without a clustered index are not supported in this version of SQL Server. Please create a clustered index and try again.

好的,所以我嘗試創建一個臨時聚集索引以刪除 PK:

CREATE CLUSTERED INDEX IX_Test ON [Friend] ([UserId],[Id])

結果是: Cannot create more than one clustered index on table 'Friend'. Drop the existing clustered index 'PK_Friend' before creating another.

太好了,一個 catch22 時刻。

如何將 UserId 列添加到我現有的 PK?

注意:從 Azure SQL 數據庫 v12 開始,這些限制不再適用。

這不是“主要索引”之類的東西。有“主鍵”之類的東西,也有“聚集索引”之類的東西。不同的概念,經常混淆。考慮到這種區別,讓我們重新審視這個問題:

Q1) 可以修改 SQL Azure 表中的聚集索引嗎?

答:是的。使用 WITH (DROP_EXISTING=ON)

create table Friend (
   UserId int not null,
   Id int not null);
go  
create clustered index cdxFriend on Friend (UserId, Id);
go
create clustered index cdxFriend on Friend (Id, UserId) with (drop_existing=on);
go

Q2) 有主鍵約束的表的聚集索引可以修改嗎?

A:是的,和上面一樣,只要不通過聚集索引強制執行主鍵約束:

create table Friend (
   UserId int not null,
   Id int not null identity(1,1),
   constraint pk_Friend primary key nonclustered (Id));
create clustered index cdxFriend on Friend (UserId, Id);
go
create clustered index cdxFriend on Friend (Id, UserId) with (drop_existing=on);
go

Q3) 可以修改表的主鍵約束嗎?

答:可以,只要不通過聚集索引強制執行主約束:

create table Friend (
   UserId int not null,
   Id int not null identity(1,1),
   constraint pk_Friend primary key nonclustered (Id));
go
create clustered index cdxFriend on Friend (UserId, Id);
go
alter table Friend drop constraint pk_Friend;
alter table Friend add constraint pk_Friend primary key nonclustered (UserId)
go

Q4) 通過聚集索引強制執行時,可以修改表的主鍵嗎?

A:是的,如果表從未有任何行:

create table Friend (
   UserId int not null,
   Id int not null identity(1,1),
   constraint pk_Friend primary key clustered (UserId, Id));
go
alter table Friend drop constraint pk_Friend;
alter table Friend add constraint pk_Friend primary key clustered (Id, UserId)
go

Q5) 如果表格被填充,可以通過聚集索引強制修改表格的主鍵嗎?

答:不可以。任何將填充的聚集索引轉換為堆的操作都將在 SQL Azure 中被阻止,即使表為空

create table Friend (
   UserId int not null,
   Id int not null identity(1,1),
   constraint pk_Friend primary key clustered (UserId, Id));
go
insert into Friend (UserId) values (1);
delete from Friend;
go
alter table Friend drop constraint pk_Friend;

附帶說明:如果表被截斷,則可以修改約束。

更改填充表的 PK 約束的解決方法是使用舊sp_rename技巧:

create table Friend (
   UserId int not null,
   Id int not null identity(1,1),
   constraint pk_Friend primary key clustered (UserId, Id));
go
insert into Friend (UserId) values (1);
go

create table FriendNew (
   UserId int not null,
   Id int not null identity(1,1),
   constraint pk_Friend_New primary key clustered (Id, UserId));
go

set identity_insert FriendNew on;
insert into FriendNew (UserId, Id) 
select UserId, Id
from Friend;
set identity_insert FriendNew off;
go

begin transaction
exec sp_rename 'Friend', 'FriendOld';
exec sp_rename 'FriendNew', 'Friend';
commit;
go

sp_help 'Friend';

sp_rename方法存在一些問題,最重要的是表的權限在重命名期間不會繼承,以及外鍵約束。

引用自:https://dba.stackexchange.com/questions/6937