如何在SQL Azure上更改现有的主键?


25

我想修改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.

太好了,赶紧行动吧。

如何将UserId列添加到现有PK中?


Answers:


34

注意:从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)可以修改具有主键约束的表的聚集索引吗?
答:是的,与上面相同,只要不通过聚簇索引强制执行主键约束:

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)通过聚簇索引强制执行时,可以修改表的主键吗?
答:是的,如果表从未有任何行:

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方法存在一些问题,最重要的是,表的权限在重命名期间不会保留,以及外键约束。


A1-A4在我的情况下没有答案。尽管我的ID不是“身份”列,但A5做到了这一点。
Magnus

sp_rename解决方法很有帮助!
贾斯汀
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.