Як я можу змінити існуючий первинний ключ у SQL Azure?


25

Я хочу змінити існуючий первинний ключ у таблиці SQL Azure.
Наразі він має один стовпець, і я хочу додати інший.

Тепер на SQL Server 2008 це був шматок пирога, якраз це робив у SSMS, poof. Зроблено. Ось так виглядає ПК, якщо я скриптую його з SQL Server:

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

Однак у SQL Azure, коли я намагаюся виконати вище, це, звичайно, не вдасться:

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

Чудово, тому я намагаюся скинути ключ:

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

Гаразд, тому я намагаюся створити тимчасовий кластерний індекс, щоб скинути ПК:

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

Результати: Cannot create more than one clustered index on table 'Friend'. Drop the existing clustered index 'PK_Friend' before creating another.

Чудово, момент22.

Як додати стовпець UserId до існуючого ПК?


Відповіді:


34

Зауважте: що стосується бази даних Azure SQL v12, ці обмеження більше не застосовуються.

Існує не таке поняття, як "первинний індекс". Існує таке поняття, як "первинний ключ", а також є таке "кластерний індекс". Виразні поняття, часто плутані. Маючи це на увазі, давайте переглянути питання:

Q1) Чи може бути змінений кластерний індекс у таблиці SQL Azure?
Відповідь: Так. Використання 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) Чи може бути змінений кластерний індекс таблиці, що має обмеження первинного ключа?
Відповідь: Так, як і вище, доки обмеження первинного ключа не буде виконано через кластерний індекс:

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) Чи можна змінити обмеження первинного ключа таблиці?
Відповідь: Так, доки основне обмеження не буде виконане через кластерний індекс:

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) Чи можна змінити первинний ключ таблиці при застосуванні через кластерний індекс?
Відповідь: Так, якщо таблиця ніколи не мала рядків:

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) Чи можна змінити первинний ключ таблиці, коли він виконується через кластерний індекс, якщо таблиця заповнена?
Відповідь: Ні. Будь-яка операція, що перетворює заселений кластерний індекс у купу, буде заблокована в SQL Azure, навіть якщо таблиця порожня :

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;

Як бічна примітка: обмеження можна змінити, якщо таблиця урізана .

Вирішення проблеми щодо обмеження ПК на заселеній таблиці полягає в тому, щоб виконувати старий добрий sp_renameтрюк:

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підходу є деякі проблеми, найголовніше те, що дозволи на столі не переносяться під час перейменування, а також зовнішні ключові обмеження.


А1-А4 у моєму випадку немає відповідей. A5 зробив трюк, хоча мій ідентифікатор не є стовпцем особи.
Магнус

sp_rename вирішення було корисним!
Джастін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.