snippetMajor
How can I alter an existing Primary Key on SQL Azure?
Viewed 0 times
canprimarysqlazurehowexistingalterkey
Problem
I want to modify an existing primary key on a SQL Azure table.
It currently has one column, and I want to add another.
Now, on SQL Server 2008 this was a piece of cake, just did it in SSMS, poof. Done.
This is how the PK looks like if I script it from SQL Server:
However, on SQL Azure, when I try to execute the above, it will of course fail:
Fine, so I try to drop the key:
Ok, so I try to create a temporary clustered index in order to drop the PK:
Which results in:
Great, a catch22 moment.
How do I add the UserId column to my existing PK?
It currently has one column, and I want to add another.
Now, on SQL Server 2008 this was a piece of cake, just did it in SSMS, poof. Done.
This is how the PK looks like if I script it from SQL Server:
ALTER TABLE [dbo].[Friend] ADD CONSTRAINT [PK_Friend] PRIMARY KEY CLUSTERED
(
[UserId] ASC,
[Id] ASC
)However, on SQL Azure, when I try to execute the above, it will of course fail:
Table 'Friend' already has a primary key defined on it.Fine, so I try to drop the key:
Tables without a clustered index are not supported in this version of SQL Server. Please create a clustered index and try again.Ok, so I try to create a temporary clustered index in order to drop the PK:
CREATE CLUSTERED INDEX IX_Test ON [Friend] ([UserId],[Id])Which results in:
Cannot create more than one clustered index on table 'Friend'. Drop the existing clustered index 'PK_Friend' before creating another.Great, a catch22 moment.
How do I add the UserId column to my existing PK?
Solution
Note: as of Azure SQL Database v12, these restrictions no longer apply.
The is no such thing as a 'primary index'. There is such a thing as a 'primary key' and also there is such a thing as a 'clustered index'. Distinct concepts, often confused. With this distinction in mind, lets revisit the question:
Q1) Can the clustered index in a SQL Azure table be modified?
A: Yes. Use
Q2) Can the clustered index of a table that has a primary key constraint be modified?
A: Yes, same as above, as long as the primary key constraint is not enforced via the clustered index:
Q3) Can the primary key constraint of a table be modified?
A: Yes, as long as the primary constraint is not enforced via the clustered index:
Q4) Can the primary key of a table be modified when is enforced via the clustered index?
A: Yes, if the table never had any rows:
Q5) Can the primary key of a table be modified when is enforced via the clustered index if the table is populated?
A: No. Any operation that converts a populated clustered index into a heap will be blocked in SQL Azure, even if the table is empty:
As a side note: the constraint can be modified if the table is truncated.
The workaround to change the PK constraint of a populated table is to do the good old
The
The is no such thing as a 'primary index'. There is such a thing as a 'primary key' and also there is such a thing as a 'clustered index'. Distinct concepts, often confused. With this distinction in mind, lets revisit the question:
Q1) Can the clustered index in a SQL Azure table be modified?
A: Yes. Use
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);
goQ2) Can the clustered index of a table that has a primary key constraint be modified?
A: Yes, same as above, as long as the primary key constraint is not enforced via the clustered index:
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);
goQ3) Can the primary key constraint of a table be modified?
A: Yes, as long as the primary constraint is not enforced via the clustered index:
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)
goQ4) Can the primary key of a table be modified when is enforced via the clustered index?
A: Yes, if the table never had any rows:
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)
goQ5) Can the primary key of a table be modified when is enforced via the clustered index if the table is populated?
A: No. Any operation that converts a populated clustered index into a heap will be blocked in SQL Azure, even if the table is empty:
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;As a side note: the constraint can be modified if the table is truncated.
The workaround to change the PK constraint of a populated table is to do the good old
sp_rename trick: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';The
sp_rename approach has some issues, most importantly being that permissions on the table do not carry over during the rename, as well as foreign key constraints.Code Snippets
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);
gocreate 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);
gocreate 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)
gocreate 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)
gocreate 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;Context
StackExchange Database Administrators Q#6937, answer score: 35
Revisions (0)
No revisions yet.