it-swarm.dev

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

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, gdy 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?

25
Magnus

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, przejdźmy ponownie do pytania:

P1) Czy można zmodyfikować indeks klastrowy w tabeli SQL Azure?
A: 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 samo jak powyżej, o ile ograniczenie klucza podstawowego nie jest egzekwowane 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?
O: Tak, dopóki podstawowe ograniczenie nie jest egzekwowane 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że być modyfikowany, 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?
O: Nie. Każda operacja, która przekształca zapełniony indeks klastrowany w 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 jest obcięta .

Obejściem problemu zmiany ograniczenia PK w zapełnionej tabeli jest zrobienie starego dobrego 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';

sp_rename podejście ma pewne problemy, najważniejsze jest to, że uprawnienia do tabeli nie są przenoszone podczas zmiany nazwy, a także ograniczenia klucza obcego.

34
Remus Rusanu