web-dev-qa-db-ja.com

SQL Azureで既存の主キーを変更するにはどうすればよいですか?

SQL Azureテーブルの既存の主キーを変更したいのですが。
現在1つの列があり、別の列を追加したいと思います。

SQL Server 2008では、これは簡単なことでしたが、SSMSで実行しただけです。できました。 SQL Serverからスクリプトを実行すると、PKは次のようになります。

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.

それでは、PKを削除するために一時的なクラスター化インデックスを作成してみます。

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.

すばらしい、catch22の瞬間。

既存のPKにUserId列を追加するにはどうすればよいですか?

25
Magnus

注:Azure SQL Database v12以降、これらの制限は適用されなくなりました。

「一次索引」のようなものではありません。 「主キー」のようなものもあり、「クラスター化インデックス」のようなものもあります。明確な概念、しばしば混同される。この違いを念頭に置いて、もう一度質問に戻りましょう。

Q1)SQL Azureテーブルのクラスター化インデックスを変更できますか?
A:はい。 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)主キー制約があるテーブルのクラスター化インデックスを変更できますか?
A:はい、上記と同じですが、クラスター化インデックスを介して主キー制約が実施されていない限り:

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)テーブルの主キー制約を変更できますか?
A:はい、一次制約がクラスター化インデックスを介して適用されない限り:

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)がクラスター化インデックスを介して適用されている場合、テーブルの主キーを変更できますか?
A:はい、テーブルに行がなかった場合:

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)テーブルにデータが入力されている場合、クラスター化インデックスを介してを適用すると、テーブルの主キーを変更できますか?
A:いいえ。テーブルが空の場合でも、データが入力されたクラスター化インデックスをヒープに変換する操作は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;

補足:テーブルがtruncateの場合、制約を変更できます。

移入されたテーブルのPK制約を変更するための回避策は、古き良き 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アプローチにはいくつかの問題があります。最も重要なのは、テーブルの権限が名前変更中に引き継がれないことと、外部キー制約です。

34
Remus Rusanu