Bagaimana saya bisa mengubah Kunci Utama yang ada pada SQL Azure?

25

Saya ingin memodifikasi kunci utama yang ada pada tabel SQL Azure.
Saat ini memiliki satu kolom, dan saya ingin menambahkan yang lain.

Sekarang, pada SQL Server 2008 ini adalah sepotong kue, lakukan saja di SSMS, poof. Selesai Ini adalah bagaimana PK terlihat jika saya skrip dari SQL Server:

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

Namun, pada SQL Azure, ketika saya mencoba mengeksekusi di atas, tentu saja akan gagal:

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

Baik, jadi saya mencoba untuk menjatuhkan kunci:

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

Oke, jadi saya mencoba membuat indeks cluster sementara untuk menjatuhkan PK:

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

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

Hebat, momen yang menarik.

Bagaimana cara menambahkan kolom UserId ke PK saya yang ada?

Magnus
sumber

Jawaban:

34

Catatan: pada Azure SQL Database v12, pembatasan ini tidak lagi berlaku.

Tidak ada yang namanya 'indeks primer'. Ada yang namanya 'kunci utama' dan ada juga yang namanya 'indeks berkerumun'. Konsep yang berbeda, sering membingungkan. Dengan perbedaan ini dalam pikiran, mari kita kembali ke pertanyaan:

T1) Dapatkah indeks berkerumun di tabel SQL Azure diubah?
A: Ya. Gunakan 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

T2) Dapatkah indeks berkerumun dari tabel yang memiliki batasan kunci primer diubah?
A: Ya, sama seperti di atas, selama batasan kunci utama tidak ditegakkan melalui indeks berkerumun:

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

T3) Dapatkah batasan kunci utama dari tabel diubah?
A: Ya, selama kendala utama tidak ditegakkan melalui indeks berkerumun:

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

T4) Bisakah kunci primer tabel diubah ketika diberlakukan melalui indeks berkerumun?
A: Ya, jika tabel tidak pernah memiliki baris:

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

T5) Dapatkah kunci utama tabel diubah ketika diberlakukan melalui indeks berkerumun jika tabel diisi?
A: Tidak. Operasi apa pun yang mengubah indeks cluster yang dihuni menjadi heap akan diblokir dalam SQL Azure, bahkan jika tabel kosong :

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;

Sebagai catatan: kendala dapat dimodifikasi jika tabel terpotong .

Solusi untuk mengubah batasan PK dari tabel berpopulasi adalah dengan melakukan sp_renametrik lama yang baik :

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_renamependekatan memiliki beberapa masalah, yang paling penting adalah bahwa hak akses atas meja tidak terbawa selama rename, serta batasan kunci asing.

Remus Rusanu
sumber
A1-A4 adalah Tidak ada jawaban dalam kasus saya. A5 melakukan trik, meskipun ID saya bukan kolom identitas.
Magnus
solusi sp_rename sangat membantu!
Justin