如何更改 SQL Azure 上的現有主鍵?
我想修改 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
方法存在一些問題,最重要的是表的權限在重命名期間不會繼承,以及外鍵約束。