it-swarm-eu.dev

Wie kann ich einen vorhandenen Primärschlüssel in SQL Azure ändern?

Ich möchte einen vorhandenen Primärschlüssel in einer SQL Azure-Tabelle ändern.
Es hat derzeit eine Spalte, und ich möchte eine weitere hinzufügen.

Auf SQL Server 2008 war dies ein Kinderspiel, nur in SSMS, poof. Erledigt. So sieht die PK aus, wenn ich sie von SQL Server aus skripte:

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

Wenn ich jedoch in SQL Azure versuche, das oben Genannte auszuführen, schlägt dies natürlich fehl:

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

Gut, also versuche ich, den Schlüssel fallen zu lassen:

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

Ok, also versuche ich, einen temporären Clustered-Index zu erstellen, um die PK zu löschen:

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

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

Großartig, ein Catch22-Moment.

Wie füge ich die UserId-Spalte zu meiner vorhandenen PK hinzu?

25
Magnus

Hinweis: Ab Azure SQL Database v12 gelten diese Einschränkungen nicht mehr.

Das ist kein "Primärindex". Es gibt so etwas wie einen "Primärschlüssel" und es gibt auch so etwas wie einen "Clustered Index". Unterschiedliche Konzepte, oft verwirrt. Lassen Sie uns angesichts dieser Unterscheidung die Frage noch einmal betrachten:

Q1) Kann der Clustered-Index in einer SQL Azure-Tabelle geändert werden?
A: Ja. Verwenden Sie 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

F2) Kann der Clustered-Index einer Tabelle mit einer Primärschlüsseleinschränkung geändert werden?
A: Ja, wie oben, solange die Primärschlüsseleinschränkung nicht über den Clustered-Index erzwungen wird:

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

F3) Kann die Primärschlüsseleinschränkung einer Tabelle geändert werden?
A: Ja, solange die primäre Einschränkung nicht über den Clustered-Index erzwungen wird:

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

F4) Kann der Primärschlüssel einer Tabelle geändert werden, wenn er über den Clustered-Index erzwungen wird?
A: Ja, wenn die Tabelle nie Zeilen hatte:

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

F5) Kann der Primärschlüssel einer Tabelle geändert werden, wenn er über den Clustered-Index erzwungen wird, wenn die Tabelle gefüllt ist?
A: Nein. Jede Operation, die einen aufgefüllten Clustered-Index in einen Heap konvertiert, wird in SQL Azure blockiert , auch wenn die Tabelle leer ist :

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;

Als Randnotiz: Die Einschränkung kann geändert werden, wenn die Tabelle abgeschnitten ist .

Die Problemumgehung zum Ändern der PK-Einschränkung einer aufgefüllten Tabelle besteht darin, das gute alte 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';

Das sp_rename Ansatz hat einige Probleme, vor allem, dass Berechtigungen für die Tabelle während des Umbenennens nicht übertragen werden, sowie Fremdschlüsseleinschränkungen.

34
Remus Rusanu