it-swarm.it

Come posso modificare una chiave primaria esistente su SQL Azure?

Voglio modificare una chiave primaria esistente su una tabella di SQL Azure.
Attualmente ha una colonna e voglio aggiungerne un'altra.

Ora, su SQL Server 2008 questo è stato un gioco da ragazzi, è stato fatto in SSMS, poof. Fatto. Ecco come appare il PK se lo script da SQL Server:

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

Tuttavia, su SQL Azure, quando provo a eseguire quanto sopra, ovviamente fallirà:

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

Bene, quindi provo a rilasciare la chiave:

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

Ok, quindi provo a creare un indice cluster temporaneo per eliminare il PK:

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

Che si traduce in: Cannot create more than one clustered index on table 'Friend'. Drop the existing clustered index 'PK_Friend' before creating another.

Ottimo, un momento di cattura22.

Come faccio ad aggiungere la colonna UserId al mio PK esistente?

25
Magnus

Nota: a partire dal database SQL di Azure v12, queste restrizioni non si applicano più.

Non esiste un "indice primario". Esiste una "chiave primaria" e esiste anche un "indice cluster". Concetti distinti, spesso confusi. Con questa distinzione in mente, lasciamo rivisitare la domanda:

Q1) È possibile modificare l'indice cluster in una tabella di SQL Azure?
A: Sì. Usa 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) È possibile modificare l'indice cluster di una tabella che ha un vincolo di chiave primaria?
A: Sì, come sopra, a condizione che il vincolo della chiave primaria non venga applicato tramite l'indice cluster:

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) È possibile modificare il vincolo chiave primaria di una tabella?
A: Sì, a condizione che il vincolo principale non venga applicato tramite l'indice cluster:

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) È possibile modificare la chiave primaria di una tabella quando viene applicata tramite l'indice cluster?
A: Sì, se la tabella non ha mai avuto righe:

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) È possibile modificare la chiave primaria di una tabella quando viene applicata tramite l'indice cluster se la tabella viene popolata?
A: No. Qualsiasi operazione che converte un indice cluster popolato in un heap verrà bloccata in SQL Azure, anche se la tabella è vuota :

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;

Come nota a margine: il vincolo può essere modificato se la tabella è troncata .

La soluzione alternativa per modificare il vincolo PK di una tabella popolata è fare il buon vecchio sp_rename trucco:

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';

Il sp_rename L'approccio presenta alcuni problemi, soprattutto perché le autorizzazioni sulla tabella non vengono riportate durante la ridenominazione, nonché i vincoli di chiave esterna.

34
Remus Rusanu