Jak mogę zmienić istniejący klucz podstawowy na SQL Azure?

25

Chcę zmodyfikować istniejący klucz podstawowy w tabeli SQL Azure.
Obecnie ma jedną kolumnę i chcę dodać kolejną.

Teraz na SQL Server 2008 było to bułka z masłem, właśnie zrobiłem to w SSMS, poof. Gotowy. Tak wygląda PK, jeśli wykonuję skrypt z SQL Server:

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

Jednak na SQL Azure, kiedy próbuję wykonać powyższe, to oczywiście się nie powiedzie:

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

W porządku, więc próbuję upuścić klucz:

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

Ok, więc próbuję utworzyć tymczasowy indeks klastrowany, aby usunąć PK:

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

Co skutkuje w: Cannot create more than one clustered index on table 'Friend'. Drop the existing clustered index 'PK_Friend' before creating another.

Świetnie, chwila złapania22.

Jak dodać kolumnę UserId do mojej istniejącej PK?

Magnus
źródło
Powiązane: stackoverflow.com/questions/5645145/…
Nick Chammas

Odpowiedzi:

34

Uwaga: od wersji 12 bazy danych SQL Azure te ograniczenia nie mają już zastosowania.

Nie ma czegoś takiego jak „indeks główny”. Istnieje coś takiego jak „klucz podstawowy”, a także coś takiego jak „indeks klastrowany”. Odrębne koncepcje, często mylone. Mając na uwadze to rozróżnienie, powróćmy do pytania:

P1) Czy można zmodyfikować indeks klastrowany w tabeli SQL Azure?
Odp .: Tak. Użyj 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) Czy można zmodyfikować indeks klastrowy tabeli z ograniczeniem klucza podstawowego?
Odp .: Tak, tak jak powyżej, o ile ograniczenie klucza podstawowego nie jest wymuszane przez indeks klastrowany:

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

P3) Czy można zmodyfikować ograniczenie klucza podstawowego tabeli?
Odp .: Tak, dopóki podstawowe ograniczenie nie jest wymuszane przez indeks klastrowany:

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

P4) Czy klucz podstawowy tabeli można modyfikować, gdy jest egzekwowany przez indeks klastrowany?
Odp .: Tak, jeśli tabela nigdy nie miała żadnych wierszy:

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

P5) Czy klucz podstawowy tabeli można modyfikować, gdy jest wymuszany przez indeks klastrowany, jeśli tabela jest zapełniona?
Odp .: Nie. Każda operacja, która konwertuje zapełniony indeks klastrowany na stertę, zostanie zablokowana na SQL Azure, nawet jeśli tabela jest pusta :

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;

Na marginesie: ograniczenie można zmodyfikować, jeśli tabela zostanie obcięta .

Obejściem problemu zmiany ograniczenia PK w zapełnionej tabeli jest wykonanie starej dobrej sp_renamesztuczki:

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_renamePodejście ma pewne problemy, najważniejsze jest, że uprawnienia na stole nie przenoszą w czasie zmiany nazwy, a także ograniczenia klucz obcy.

Remus Rusanu
źródło
A1-A4 nie ma odpowiedzi w moim przypadku. A5 załatwiło sprawę, chociaż mój identyfikator nie jest kolumną tożsamości.
Magnus,
Obejście sp_rename było pomocne!
Justin