Comment puis-je modifier une clé primaire existante sur SQL Azure?


25

Je souhaite modifier une clé primaire existante sur une table SQL Azure.
Il a actuellement une colonne, et je veux en ajouter une autre.

Maintenant, sur SQL Server 2008, c'était un morceau de gâteau, je viens de le faire dans SSMS, pouf. Terminé. Voici à quoi ressemble le PK si je le script à partir de SQL Server:

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

Cependant, sur SQL Azure, lorsque j'essaie d'exécuter ce qui précède, cela échouera bien sûr:

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

Très bien, alors j'essaie de laisser tomber la clé:

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

Ok, j'essaie donc de créer un index cluster temporaire afin de supprimer le PK:

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

Ce qui se traduit par: Cannot create more than one clustered index on table 'Friend'. Drop the existing clustered index 'PK_Friend' before creating another.

Super, un moment catch22.

Comment ajouter la colonne UserId à mon PK existant?


Réponses:


34

Remarque: depuis Azure SQL Database v12, ces restrictions ne s'appliquent plus.

Il n'y a rien de tel qu'un «indice primaire». Il existe une «clé primaire» et un «index clusterisé». Concepts distincts, souvent confus. Avec cette distinction à l'esprit, revenons à la question:

Q1) L'index cluster dans une table SQL Azure peut-il être modifié?
R: Oui. Utilisation 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) L'index cluster d'une table qui a une contrainte de clé primaire peut-il être modifié?
R: Oui, comme ci-dessus, tant que la contrainte de clé primaire n'est pas appliquée via l'index clusterisé:

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) La contrainte de clé primaire d'une table peut-elle être modifiée?
R: Oui, tant que la contrainte principale n'est pas appliquée via l'index clusterisé:

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) La clé primaire d'une table peut-elle être modifiée lorsqu'elle est appliquée via l'index clusterisé?
R: Oui, si la table n'a jamais eu de lignes:

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) La clé primaire d'une table peut-elle être modifiée lorsqu'elle est appliquée via l'index clusterisé si la table est remplie?
R: Non. Toute opération qui convertit un index cluster rempli en un tas sera bloquée dans SQL Azure, même si la table est vide :

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;

En remarque: la contrainte peut être modifiée si le tableau est tronqué .

La solution de contournement pour modifier la contrainte PK d'une table remplie est de faire le bon vieux sp_renametruc:

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';

L' sp_renameapproche présente certains problèmes, le plus important étant que les autorisations sur la table ne sont pas transférées pendant le renommage, ainsi que les contraintes de clé étrangère.


A1-A4 sont Aucune réponse dans mon cas. A5 a fait l'affaire, bien que mon identifiant ne soit pas une colonne d'identité.
Magnus

La solution de contournement de sp_rename a été utile!
Justin
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.